You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/02/18 09:55:58 UTC

[isis] branch master updated: ISIS-2158: simplify QueryResultCache usage

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 8040ab2  ISIS-2158: simplify QueryResultCache usage
8040ab2 is described below

commit 8040ab2d3c32e388151ce631001aaa363508b704
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Feb 18 10:55:45 2020 +0100

    ISIS-2158: simplify QueryResultCache usage
---
 .../queryresultscache/QueryResultsCache.java       |  37 ++++++-
 .../QueryResultsCacheDefault.java                  | 114 ++++++++++++++++-----
 .../isis/applib/services/wrapper/AsyncWrap.java    |  84 ++++-----------
 .../core/commons/handler/MethodReferences.java     |  95 +++++++++++++++++
 .../runtimeservices/wrapper/AsyncWrapDefault.java  |  16 +--
 5 files changed, 248 insertions(+), 98 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java b/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
index 33018f2..a3a6b4d 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
@@ -21,6 +21,15 @@ package org.apache.isis.applib.services.queryresultscache;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
 
+import org.apache.isis.core.commons.handler.MethodReferences.Call0;
+import org.apache.isis.core.commons.handler.MethodReferences.Call1;
+import org.apache.isis.core.commons.handler.MethodReferences.Call2;
+import org.apache.isis.core.commons.handler.MethodReferences.Call3;
+import org.apache.isis.core.commons.handler.MethodReferences.Call4;
+import org.apache.isis.core.commons.handler.MethodReferences.Call5;
+
+
+
 /**
  * This service (API and implementation) provides a mechanism by which idempotent query results can be cached for the duration of an interaction.
  * Most commonly this allows otherwise &quot;naive&quot; - eg that makes a repository call many times within a loop - to
@@ -33,6 +42,30 @@ import java.util.concurrent.Callable;
  */
 public interface QueryResultsCache {
 
+    // -- INTERFACE
+
+    public <T> T execute(Callable<T> callable, Class<?> callingClass, String methodName, Object... keys);
+
+    <R> R execute(Call0<? extends R> action, Class<?> callingClass, String methodName);
+    
+    <R, A0> R execute(Call1<? extends R, A0> action, Class<?> callingClass, String methodName,
+            A0 arg0);
+    
+    <R, A0, A1> R execute(Call2<? extends R, A0, A1> action, Class<?> callingClass, String methodName, 
+            A0 arg0, A1 arg1);
+    
+    <R, A0, A1, A2> R execute(Call3<? extends R, A0, A1, A2> action, Class<?> callingClass, String methodName,
+            A0 arg0, A1 arg1, A2 arg2);
+    
+    <R, A0, A1, A2, A3> R execute(Call4<? extends R, A0, A1, A2, A3> action, Class<?> callingClass, String methodName,
+            A0 arg0, A1 arg1, A2 arg2, A3 arg3);
+    
+    <R, A0, A1, A2, A3, A4> R execute(Call5<? extends R, A0, A1, A2, A3, A4> action, Class<?> callingClass, String methodName,
+            A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4);
+    
+    public void resetForNextTransaction();
+    
+    
     // -- KEY
 
     public static class Key {
@@ -116,10 +149,6 @@ public interface QueryResultsCache {
         }
     }
 
-    // -- INTERFACE
-
-    public <T> T execute(Callable<T> callable, Class<?> callingClass, String methodName, Object... keys);
 
-    public void resetForNextTransaction();
 
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCacheDefault.java b/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCacheDefault.java
index 6f3e79c..5ddf15c 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCacheDefault.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCacheDefault.java
@@ -32,6 +32,12 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.WithTransactionScope;
+import org.apache.isis.core.commons.handler.MethodReferences.Call0;
+import org.apache.isis.core.commons.handler.MethodReferences.Call1;
+import org.apache.isis.core.commons.handler.MethodReferences.Call2;
+import org.apache.isis.core.commons.handler.MethodReferences.Call3;
+import org.apache.isis.core.commons.handler.MethodReferences.Call4;
+import org.apache.isis.core.commons.handler.MethodReferences.Call5;
 import org.apache.isis.core.commons.internal.base._Casts;
 import org.apache.isis.core.commons.internal.base._NullSafe;
 import org.apache.isis.core.commons.internal.collections._Maps;
@@ -58,6 +64,64 @@ import lombok.extern.log4j.Log4j2;
 public class QueryResultsCacheDefault implements QueryResultsCache, WithTransactionScope {
 
     private final Map<Key, Value<?>> cache = _Maps.newHashMap();
+    
+    @Override
+    public <R> R execute(Call0<? extends R> action, Class<?> callingClass, String methodName) {
+        if(isIgnoreCache()) {
+            return action.call();
+        }
+        final Key cacheKey = new Key(callingClass, methodName);
+        return executeWithCaching(()->action.call(), cacheKey);
+    }
+
+    @Override
+    public <R, A0> R execute(Call1<? extends R, A0> action, Class<?> callingClass, String methodName, A0 arg0) {
+        if(isIgnoreCache()) {
+            return action.call(arg0);
+        }
+        final Key cacheKey = new Key(callingClass, methodName, arg0);
+        return executeWithCaching(()->action.call(arg0), cacheKey);
+    }
+
+    @Override
+    public <R, A0, A1> R execute(Call2<? extends R, A0, A1> action, Class<?> callingClass, String methodName, A0 arg0,
+            A1 arg1) {
+        if(isIgnoreCache()) {
+            return action.call(arg0, arg1);
+        }
+        final Key cacheKey = new Key(callingClass, methodName, arg0, arg1);
+        return executeWithCaching(()->action.call(arg0, arg1), cacheKey);
+    }
+
+    @Override
+    public <R, A0, A1, A2> R execute(Call3<? extends R, A0, A1, A2> action, Class<?> callingClass, String methodName,
+            A0 arg0, A1 arg1, A2 arg2) {
+        if(isIgnoreCache()) {
+            return action.call(arg0, arg1, arg2);
+        }
+        final Key cacheKey = new Key(callingClass, methodName, arg0, arg1, arg2);
+        return executeWithCaching(()->action.call(arg0, arg1, arg2), cacheKey);
+    }
+
+    @Override
+    public <R, A0, A1, A2, A3> R execute(Call4<? extends R, A0, A1, A2, A3> action, Class<?> callingClass,
+            String methodName, A0 arg0, A1 arg1, A2 arg2, A3 arg3) {
+        if(isIgnoreCache()) {
+            return action.call(arg0, arg1, arg2, arg3);
+        }
+        final Key cacheKey = new Key(callingClass, methodName, arg0, arg1, arg2, arg3);
+        return executeWithCaching(()->action.call(arg0, arg1, arg2, arg3), cacheKey);
+    }
+
+    @Override
+    public <R, A0, A1, A2, A3, A4> R execute(Call5<? extends R, A0, A1, A2, A3, A4> action, Class<?> callingClass,
+            String methodName, A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
+        if(isIgnoreCache()) {
+            return action.call(arg0, arg1, arg2, arg3, arg4);
+        }
+        final Key cacheKey = new Key(callingClass, methodName, arg0, arg1, arg2, arg3, arg4);
+        return executeWithCaching(()->action.call(arg0, arg1, arg2, arg3, arg4), cacheKey);
+    }
 
     @Override
     public <T> T execute(
@@ -76,18 +140,6 @@ public class QueryResultsCacheDefault implements QueryResultsCache, WithTransact
         return executeWithCaching(callable, cacheKey);
     }
 
-//XXX not used    
-//    private <T> T execute(final Callable<T> callable, final Key cacheKey) {
-//        if(isIgnoreCache()) {
-//            try {
-//                return callable.call();
-//            } catch (Exception e) {
-//                throw new RuntimeException(e);
-//            }
-//        }
-//        return executeWithCaching(callable, cacheKey);
-//    }
-
     private <T> T executeWithCaching(final Callable<T> callable, final Key cacheKey) {
         try {
             final Value<?> cacheValue = cache.get(cacheKey);
@@ -113,18 +165,6 @@ public class QueryResultsCacheDefault implements QueryResultsCache, WithTransact
         }
     }
 
-//XXX not used    
-//    private <T> Value<T> get(final Class<?> callingClass, final String methodName, final Object... keys) {
-//        return get(new Key(callingClass, methodName, keys));
-//    }
-//
-//    @SuppressWarnings("unchecked")
-//    private <T> Value<T> get(final Key cacheKey) {
-//        Value<T> value = (Value<T>) cache.get(cacheKey);
-//        logHitOrMiss(cacheKey, value);
-//        return value;
-//    }
-
     private <T> void put(final Key cacheKey, final T result) {
         log.debug("PUT: {}", cacheKey);
         cache.put(cacheKey, new Value<T>(result));
@@ -159,5 +199,31 @@ public class QueryResultsCacheDefault implements QueryResultsCache, WithTransact
         return _NullSafe.stream(cacheControl)
                 .anyMatch(c->c.isIgnoreCache());
     }
+    
+    // -- REMOVED
+    
+  //XXX not used    
+//  private <T> Value<T> get(final Class<?> callingClass, final String methodName, final Object... keys) {
+//      return get(new Key(callingClass, methodName, keys));
+//  }
+//
+//  @SuppressWarnings("unchecked")
+//  private <T> Value<T> get(final Key cacheKey) {
+//      Value<T> value = (Value<T>) cache.get(cacheKey);
+//      logHitOrMiss(cacheKey, value);
+//      return value;
+//  }
+    
+  //XXX not used    
+//  private <T> T execute(final Callable<T> callable, final Key cacheKey) {
+//      if(isIgnoreCache()) {
+//          try {
+//              return callable.call();
+//          } catch (Exception e) {
+//              throw new RuntimeException(e);
+//          }
+//      }
+//      return executeWithCaching(callable, cacheKey);
+//  }
 
 }
\ No newline at end of file
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/AsyncWrap.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/AsyncWrap.java
index 9b4bdd3..f042d97 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/AsyncWrap.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/AsyncWrap.java
@@ -24,6 +24,16 @@ import java.util.function.Consumer;
 
 import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
 import org.apache.isis.core.commons.collections.ImmutableEnumSet;
+import org.apache.isis.core.commons.handler.MethodReferences.Call1;
+import org.apache.isis.core.commons.handler.MethodReferences.Call2;
+import org.apache.isis.core.commons.handler.MethodReferences.Call3;
+import org.apache.isis.core.commons.handler.MethodReferences.Call4;
+import org.apache.isis.core.commons.handler.MethodReferences.Call5;
+import org.apache.isis.core.commons.handler.MethodReferences.Run1;
+import org.apache.isis.core.commons.handler.MethodReferences.Run2;
+import org.apache.isis.core.commons.handler.MethodReferences.Run3;
+import org.apache.isis.core.commons.handler.MethodReferences.Run4;
+import org.apache.isis.core.commons.handler.MethodReferences.Run5;
 
 /**
  * Binds to a domain object, to prepare for type-safe asynchronous action invocation.
@@ -35,60 +45,6 @@ import org.apache.isis.core.commons.collections.ImmutableEnumSet;
  */
 public interface AsyncWrap<T> {
 
-    // -- METHOD REFERENCE MATCHERS (WITHOUT RETURN VALUE)
-    
-    @FunctionalInterface
-    public static interface Run0<T> {
-        void run(T obj);
-    }
-    
-    @FunctionalInterface
-    public static interface Run1<T, A1> {
-        void run(T obj, A1 arg1);
-    }
-    
-    @FunctionalInterface
-    public static interface Run2<T, A1, A2> {
-        void run(T obj, A1 arg1, A2 arg2);
-    }
-    
-    @FunctionalInterface
-    public static interface Run3<T, A1, A2, A3> {
-        void run(T obj, A1 arg1, A2 arg2, A3 arg3);
-    }
-    
-    @FunctionalInterface
-    public static interface Run4<T, A1, A2, A3, A4> {
-        void run(T obj, A1 arg1, A2 arg2, A3 arg3, A4 arg4);
-    }
-    
-    // -- METHOD REFERENCE MATCHERS (WITH RETURN VALUE)
-    
-    @FunctionalInterface
-    public static interface Call0<T, R> {
-        R call(T obj);
-    }
-    
-    @FunctionalInterface
-    public static interface Call1<T, R, A1> {
-        R call(T obj, A1 arg1);
-    }
-    
-    @FunctionalInterface
-    public static interface Call2<T, R, A1, A2> {
-        R call(T obj, A1 arg1, A2 arg2);
-    }
-    
-    @FunctionalInterface
-    public static interface Call3<T, R, A1, A2, A3> {
-        R call(T obj, A1 arg1, A2 arg2, A3 arg3);
-    }
-    
-    @FunctionalInterface
-    public static interface Call4<T, R, A1, A2, A3, A4> {
-        R call(T obj, A1 arg1, A2 arg2, A3 arg3, A4 arg4);
-    }
-    
     // -- CONFIGURATION
     
     ExecutorService getExecutor();
@@ -101,30 +57,30 @@ public interface AsyncWrap<T> {
     
     // -- INVOCATION (WITH RETURN VALUE)
     
-    <R> Future<R> call(Call0<? super T, ? extends R> action);
+    <R> Future<R> call(Call1<? extends R, ? super T> action);
     
-    <R, A1> Future<R> call(Call1<? super T, ? extends R, A1> action, 
+    <R, A1> Future<R> call(Call2<? extends R, ? super T, A1> action, 
             A1 arg1);
     
-    <R, A1, A2> Future<R> call(Call2<? super T, ? extends R, A1, A2> action, 
+    <R, A1, A2> Future<R> call(Call3<? extends R, ? super T, A1, A2> action, 
             A1 arg1, A2 arg2);
     
-    <R, A1, A2, A3> Future<R> call(Call3<? super T, ? extends R, A1, A2, A3> action, 
+    <R, A1, A2, A3> Future<R> call(Call4<? extends R, ? super T, A1, A2, A3> action, 
             A1 arg1, A2 arg2, A3 arg3);
     
-    <R, A1, A2, A3, A4> Future<R> call(Call4<? super T, ? extends R, A1, A2, A3, A4> action, 
+    <R, A1, A2, A3, A4> Future<R> call(Call5<? extends R, ? super T, A1, A2, A3, A4> action, 
             A1 arg1, A2 arg2, A3 arg3, A4 arg4);
     
     // -- INVOCATION (WITHOUT RETURN VALUE)
     
-    default Future<Void> run(Run0<? super T> action) {
+    default Future<Void> run(Run1<? super T> action) {
         return call(obj->{
             action.run(obj); 
             return null;
         });
     }
     
-    default <A1> Future<Void> run(Run1<? super T, A1> action, 
+    default <A1> Future<Void> run(Run2<? super T, A1> action, 
             A1 arg1) {
         
         return call(obj->{
@@ -133,7 +89,7 @@ public interface AsyncWrap<T> {
         });
     }
     
-    default <A1, A2> Future<Void> run(Run2<? super T, A1, A2> action, 
+    default <A1, A2> Future<Void> run(Run3<? super T, A1, A2> action, 
             A1 arg1, A2 arg2) {
         
         return call(obj->{
@@ -142,7 +98,7 @@ public interface AsyncWrap<T> {
         });
     }
     
-    default <A1, A2, A3> Future<Void> run(Run3<? super T, A1, A2, A3> action, 
+    default <A1, A2, A3> Future<Void> run(Run4<? super T, A1, A2, A3> action, 
             A1 arg1, A2 arg2, A3 arg3) {
         
         return call(obj->{
@@ -151,7 +107,7 @@ public interface AsyncWrap<T> {
         });
     }
     
-    default <A1, A2, A3, A4> Future<Void> run(Run4<? super T, A1, A2, A3, A4> action, 
+    default <A1, A2, A3, A4> Future<Void> run(Run5<? super T, A1, A2, A3, A4> action, 
             A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
         
         return call(obj->{
diff --git a/core/commons/src/main/java/org/apache/isis/core/commons/handler/MethodReferences.java b/core/commons/src/main/java/org/apache/isis/core/commons/handler/MethodReferences.java
new file mode 100644
index 0000000..2fa4266
--- /dev/null
+++ b/core/commons/src/main/java/org/apache/isis/core/commons/handler/MethodReferences.java
@@ -0,0 +1,95 @@
+/*
+ *  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.isis.core.commons.handler;
+
+import lombok.experimental.UtilityClass;
+
+/**
+ * 
+ * @since 2.0
+ *
+ */
+@UtilityClass
+public class MethodReferences {
+
+    // -- METHOD REFERENCE MATCHERS (WITHOUT RETURN VALUE)
+    
+    @FunctionalInterface
+    public static interface Run0 {
+        void run();
+    }
+    
+    @FunctionalInterface
+    public static interface Run1<A0> {
+        void run(A0 arg0);
+    }
+    
+    @FunctionalInterface
+    public static interface Run2<A0, A1> {
+        void run(A0 arg0, A1 arg1);
+    }
+    
+    @FunctionalInterface
+    public static interface Run3<A0, A1, A2> {
+        void run(A0 arg0, A1 arg1, A2 arg2);
+    }
+    
+    @FunctionalInterface
+    public static interface Run4<A0, A1, A2, A3> {
+        void run(A0 arg0, A1 arg1, A2 arg2, A3 arg3);
+    }
+    
+    @FunctionalInterface
+    public static interface Run5<A0, A1, A2, A3, A4> {
+        void run(A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4);
+    }
+    
+    // -- METHOD REFERENCE MATCHERS (WITH RETURN VALUE)
+    
+    @FunctionalInterface
+    public static interface Call0<R> {
+        R call();
+    }
+    
+    @FunctionalInterface
+    public static interface Call1<R, A0> {
+        R call(A0 arg0);
+    }
+    
+    @FunctionalInterface
+    public static interface Call2<R, A0, A1> {
+        R call(A0 arg0, A1 arg1);
+    }
+    
+    @FunctionalInterface
+    public static interface Call3<R, A0, A1, A2> {
+        R call(A0 arg0, A1 arg1, A2 arg2);
+    }
+    
+    @FunctionalInterface
+    public static interface Call4<R, A0, A1, A2, A3> {
+        R call(A0 arg0, A1 arg1, A2 arg2, A3 arg3);
+    }
+    
+    @FunctionalInterface
+    public static interface Call5<R, A0, A1, A2, A3, A4> {
+        R call(A0 arg0, A1 arg1, A2 arg2, A3 arg3, A4 arg4);
+    }
+    
+}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/AsyncWrapDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/AsyncWrapDefault.java
index d660782..b441369 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/AsyncWrapDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/AsyncWrapDefault.java
@@ -30,6 +30,11 @@ import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.wrapper.WrapperFactory.ExecutionMode;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.core.commons.collections.ImmutableEnumSet;
+import org.apache.isis.core.commons.handler.MethodReferences.Call1;
+import org.apache.isis.core.commons.handler.MethodReferences.Call2;
+import org.apache.isis.core.commons.handler.MethodReferences.Call3;
+import org.apache.isis.core.commons.handler.MethodReferences.Call4;
+import org.apache.isis.core.commons.handler.MethodReferences.Call5;
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.runtime.context.IsisContext;
 import org.apache.isis.core.runtime.session.IsisSessionFactory;
@@ -41,7 +46,6 @@ import lombok.NonNull;
 import lombok.With;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
-
 /**
  * 
  * @since 2.0
@@ -83,7 +87,7 @@ class AsyncWrapDefault<T> implements AsyncWrap<T> {
     // -- METHOD REFERENCE MATCHERS (WITH RETURN VALUE)
     
     @Override
-    public <R> Future<R> call(Call0<? super T, ? extends R> action) {
+    public <R> Future<R> call(Call1<? extends R, ? super T> action) {
         
         if(shouldValidate()) {
             // do validation synchronous (with the calling thread)
@@ -103,7 +107,7 @@ class AsyncWrapDefault<T> implements AsyncWrap<T> {
 
 
     @Override
-    public <R, A1> Future<R> call(Call1<? super T, ? extends R, A1> action, A1 arg1) {
+    public <R, A1> Future<R> call(Call2<? extends R, ? super T, A1> action, A1 arg1) {
         
         if(shouldValidate()) {
             // do validation synchronous (with the calling thread)
@@ -122,7 +126,7 @@ class AsyncWrapDefault<T> implements AsyncWrap<T> {
     }
 
     @Override
-    public <R, A1, A2> Future<R> call(Call2<? super T, ? extends R, A1, A2> action, A1 arg1, A2 arg2) {
+    public <R, A1, A2> Future<R> call(Call3<? extends R, ? super T, A1, A2> action, A1 arg1, A2 arg2) {
 
         if(shouldValidate()) {
             // do validation synchronous (with the calling thread)
@@ -142,7 +146,7 @@ class AsyncWrapDefault<T> implements AsyncWrap<T> {
     
 
     @Override
-    public <R, A1, A2, A3> Future<R> call(Call3<? super T, ? extends R, A1, A2, A3> action, 
+    public <R, A1, A2, A3> Future<R> call(Call4<? extends R, ? super T, A1, A2, A3> action, 
             A1 arg1, A2 arg2, A3 arg3) {
         
         if(shouldValidate()) {
@@ -163,7 +167,7 @@ class AsyncWrapDefault<T> implements AsyncWrap<T> {
 
 
     @Override
-    public <R, A1, A2, A3, A4> Future<R> call(Call4<? super T, ? extends R, A1, A2, A3, A4> action, 
+    public <R, A1, A2, A3, A4> Future<R> call(Call5<? extends R, ? super T, A1, A2, A3, A4> action, 
             A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
 
         if(shouldValidate()) {