diff options
author | Jose <jose@zeroc.com> | 2019-07-18 23:51:08 +0200 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2019-07-18 23:51:08 +0200 |
commit | fc886b010c01cccb8cca3ac4d92f1ebd7fc72295 (patch) | |
tree | 51cf00a4a955efecc9c94527aeafcb25ffbe57b9 /java | |
parent | Simplify OutputStream creation (diff) | |
parent | Fixed non-thread safe AMD dispatch, fixes #448 (#449) (diff) | |
download | ice-fc886b010c01cccb8cca3ac4d92f1ebd7fc72295.tar.bz2 ice-fc886b010c01cccb8cca3ac4d92f1ebd7fc72295.tar.xz ice-fc886b010c01cccb8cca3ac4d92f1ebd7fc72295.zip |
Merge remote-tracking branch 'origin/3.7' into swift
Diffstat (limited to 'java')
16 files changed, 215 insertions, 32 deletions
diff --git a/java/gradle/wrapper/gradle-wrapper.jar b/java/gradle/wrapper/gradle-wrapper.jar Binary files differindex 29953ea141f..94336fcae91 100644 --- a/java/gradle/wrapper/gradle-wrapper.jar +++ b/java/gradle/wrapper/gradle-wrapper.jar diff --git a/java/gradle/wrapper/gradle-wrapper.properties b/java/gradle/wrapper/gradle-wrapper.properties index e0b3fb8d70b..290541c7386 100644 --- a/java/gradle/wrapper/gradle-wrapper.properties +++ b/java/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/Blobject.java b/java/src/Ice/src/main/java/com/zeroc/Ice/Blobject.java index e23f5e7e6a5..9d3637badaf 100644 --- a/java/src/Ice/src/main/java/com/zeroc/Ice/Blobject.java +++ b/java/src/Ice/src/main/java/com/zeroc/Ice/Blobject.java @@ -39,6 +39,6 @@ public interface Blobject extends com.zeroc.Ice.Object { byte[] inEncaps = in.readParamEncaps(); com.zeroc.Ice.Object.Ice_invokeResult r = ice_invoke(inEncaps, current); - return in.setResult(in.writeParamEncaps(r.outParams, r.returnValue)); + return in.setResult(in.writeParamEncaps(in.getAndClearCachedOutputStream(), r.outParams, r.returnValue)); } } diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/BlobjectAsync.java b/java/src/Ice/src/main/java/com/zeroc/Ice/BlobjectAsync.java index cb9ddadfd16..6a148071905 100644 --- a/java/src/Ice/src/main/java/com/zeroc/Ice/BlobjectAsync.java +++ b/java/src/Ice/src/main/java/com/zeroc/Ice/BlobjectAsync.java @@ -45,7 +45,9 @@ public interface BlobjectAsync extends com.zeroc.Ice.Object { byte[] inEncaps = in.readParamEncaps(); CompletableFuture<OutputStream> f = new CompletableFuture<>(); - ice_invokeAsync(inEncaps, current).whenComplete((result, ex) -> + CompletionStage<Object.Ice_invokeResult> s = ice_invokeAsync(inEncaps, current); + final OutputStream cached = in.getAndClearCachedOutputStream(); // If an output stream is cached, re-use it + s.whenComplete((result, ex) -> { if(ex != null) { @@ -53,7 +55,7 @@ public interface BlobjectAsync extends com.zeroc.Ice.Object } else { - f.complete(in.writeParamEncaps(result.outParams, result.returnValue)); + f.complete(in.writeParamEncaps(cached, result.outParams, result.returnValue)); } }); return f; diff --git a/java/src/Ice/src/main/java/com/zeroc/Ice/DispatchInterceptor.java b/java/src/Ice/src/main/java/com/zeroc/Ice/DispatchInterceptor.java index d825707630e..8523bdc929d 100644 --- a/java/src/Ice/src/main/java/com/zeroc/Ice/DispatchInterceptor.java +++ b/java/src/Ice/src/main/java/com/zeroc/Ice/DispatchInterceptor.java @@ -36,6 +36,22 @@ public abstract class DispatchInterceptor implements com.zeroc.Ice.Object public CompletionStage<OutputStream> _iceDispatch(com.zeroc.IceInternal.Incoming in, Current current) throws UserException { - return dispatch(in); + try + { + return dispatch(in); + } + catch(java.lang.Throwable ex) + { + // + // If the input parameters weren't read, make sure we skip them here. It's needed to read the + // encoding version used by the client to eventually marshal the user exception. It's also needed + // if we dispatch a batch oneway request to read the next batch request. + // + if(current.encoding == null || (current.encoding.major == 0 && current.encoding.minor == 0)) + { + in.skipReadParams(); + } + throw ex; + } } } diff --git a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java index dc5a60d390a..f8d899ae365 100644 --- a/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java +++ b/java/src/Ice/src/main/java/com/zeroc/IceInternal/Incoming.java @@ -271,6 +271,13 @@ final public class Incoming implements com.zeroc.Ice.Request public <T> CompletionStage<OutputStream> setResultFuture(CompletionStage<T> f, Write<T> write) { + final OutputStream cached = getAndClearCachedOutputStream(); // If an output stream is cached, re-use it + + // + // NOTE: it's important that the continuation doesn't mutate the Incoming state to + // guarantee thread-safety. Multiple continuations can execute concurrently if the + // user installed a dispatch interceptor and the dispatch is retried. + // final CompletableFuture<OutputStream> r = new CompletableFuture<OutputStream>(); f.whenComplete((result, ex) -> { @@ -280,7 +287,7 @@ final public class Incoming implements com.zeroc.Ice.Request } else { - OutputStream os = startWriteParams(); + OutputStream os = startWriteParams(cached); write.write(os, result); endWriteParams(os); r.complete(os); @@ -291,6 +298,13 @@ final public class Incoming implements com.zeroc.Ice.Request public CompletionStage<OutputStream> setResultFuture(CompletionStage<Void> f) { + final OutputStream cached = getAndClearCachedOutputStream(); // If an output stream is cached, re-use it + + // + // NOTE: it's important that the continuation doesn't mutate the Incoming state to + // guarantee thread-safety. Multiple continuations can execute concurrently if the + // user installed a dispatch interceptor and the dispatch is retried. + // final CompletableFuture<OutputStream> r = new CompletableFuture<OutputStream>(); f.whenComplete((result, ex) -> { @@ -300,7 +314,7 @@ final public class Incoming implements com.zeroc.Ice.Request } else { - r.complete(writeEmptyParams()); + r.complete(writeEmptyParams(cached)); } }); return r; @@ -448,6 +462,20 @@ final public class Incoming implements com.zeroc.Ice.Request _format = format; } + public OutputStream getAndClearCachedOutputStream() + { + if(_response) + { + OutputStream cached = _os; + _os = null; + return cached; + } + else + { + return null; // Don't consume unnecessarily the output stream if we are dispatching a oneway request + } + } + static public OutputStream createResponseOutputStream(Current current) { OutputStream os = new OutputStream(current.adapter.getCommunicator(), Protocol.currentProtocolEncoding); @@ -457,17 +485,18 @@ final public class Incoming implements com.zeroc.Ice.Request return os; } - public OutputStream startWriteParams() + private OutputStream startWriteParams(OutputStream os) { if(!_response) { throw new com.zeroc.Ice.MarshalException("can't marshal out parameters for oneway dispatch"); } - // If there's an output stream set, re-use it for the response - OutputStream os = _os == null ? new OutputStream(_instance, Protocol.currentProtocolEncoding) : _os; + if(os == null) // Create the output stream if none is provided + { + os = new OutputStream(_instance, Protocol.currentProtocolEncoding); + } assert(os.pos() == 0); - _os = null; os.writeBlob(Protocol.replyHdr); os.writeInt(_current.requestId); os.writeByte(ReplyStatus.replyOK); @@ -475,6 +504,11 @@ final public class Incoming implements com.zeroc.Ice.Request return os; } + public OutputStream startWriteParams() + { + return startWriteParams(getAndClearCachedOutputStream()); + } + public void endWriteParams(OutputStream os) { if(_response) @@ -483,14 +517,15 @@ final public class Incoming implements com.zeroc.Ice.Request } } - public OutputStream writeEmptyParams() + private OutputStream writeEmptyParams(OutputStream os) { if(_response) { - // If there's an output stream set, re-use it for the response - OutputStream os = _os == null ? new OutputStream(_instance, Protocol.currentProtocolEncoding) : _os; + if(os == null) // Create the output stream if none is provided + { + os = new OutputStream(_instance, Protocol.currentProtocolEncoding); + } assert(os.pos() == 0); - _os = null; os.writeBlob(Protocol.replyHdr); os.writeInt(_current.requestId); os.writeByte(ReplyStatus.replyOK); @@ -503,7 +538,12 @@ final public class Incoming implements com.zeroc.Ice.Request } } - public OutputStream writeParamEncaps(byte[] v, boolean ok) + public OutputStream writeEmptyParams() + { + return writeEmptyParams(getAndClearCachedOutputStream()); + } + + public OutputStream writeParamEncaps(OutputStream os, byte[] v, boolean ok) { if(!ok && _observer != null) { @@ -512,10 +552,11 @@ final public class Incoming implements com.zeroc.Ice.Request if(_response) { - // If there's an output stream set, re-use it for the response - OutputStream os = _os == null ? new OutputStream(_instance, Protocol.currentProtocolEncoding) : _os; + if(os == null) // Create the output stream if none is provided + { + os = new OutputStream(_instance, Protocol.currentProtocolEncoding); + } assert(os.pos() == 0); - _os = null; os.writeBlob(Protocol.replyHdr); os.writeInt(_current.requestId); os.writeByte(ok ? ReplyStatus.replyOK : ReplyStatus.replyUserException); diff --git a/java/test/android/controller/build.gradle b/java/test/android/controller/build.gradle index 2e5f8ca9e75..e8f9040f821 100644 --- a/java/test/android/controller/build.gradle +++ b/java/test/android/controller/build.gradle @@ -11,7 +11,7 @@ buildscript { } } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.4.2' classpath 'gradle.plugin.com.zeroc.gradle.ice-builder:slice:1.4.7' } } diff --git a/java/test/android/controller/gradle/wrapper/gradle-wrapper.jar b/java/test/android/controller/gradle/wrapper/gradle-wrapper.jar Binary files differindex 29953ea141f..87b738cbd05 100644 --- a/java/test/android/controller/gradle/wrapper/gradle-wrapper.jar +++ b/java/test/android/controller/gradle/wrapper/gradle-wrapper.jar diff --git a/java/test/android/controller/gradle/wrapper/gradle-wrapper.properties b/java/test/android/controller/gradle/wrapper/gradle-wrapper.properties index e0b3fb8d70b..558870dad58 100644 --- a/java/test/android/controller/gradle/wrapper/gradle-wrapper.properties +++ b/java/test/android/controller/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/java/test/android/controller/gradlew b/java/test/android/controller/gradlew index cccdd3d517f..af6708ff229 100755 --- a/java/test/android/controller/gradlew +++ b/java/test/android/controller/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/java/test/android/controller/gradlew.bat b/java/test/android/controller/gradlew.bat index f9553162f12..6d57edc706c 100644 --- a/java/test/android/controller/gradlew.bat +++ b/java/test/android/controller/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/java/test/android/controller/settings.gradle b/java/test/android/controller/settings.gradle new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/java/test/android/controller/settings.gradle diff --git a/java/test/src/main/java/test/Ice/interceptor/Client.java b/java/test/src/main/java/test/Ice/interceptor/Client.java index 9bd89a14661..bbb62f152b9 100644 --- a/java/test/src/main/java/test/Ice/interceptor/Client.java +++ b/java/test/src/main/java/test/Ice/interceptor/Client.java @@ -89,6 +89,11 @@ public class Client extends test.TestHelper test(interceptor.getLastOperation().equals("badSystemAdd")); test(!interceptor.getLastStatus()); out.println("ok"); + + out.print("testing exceptions raised by the interceptor... "); + out.flush(); + testInterceptorExceptions(prx); + out.println("ok"); } private void runAmdTest(MyObjectPrx prx, InterceptorI interceptor, PrintWriter out) @@ -106,6 +111,16 @@ public class Client extends test.TestHelper test(prx.amdAddWithRetry(33, 12) == 45); test(interceptor.getLastOperation().equals("amdAddWithRetry")); test(interceptor.getLastStatus()); + { + java.util.Map<String, String> ctx = new java.util.HashMap<>(); + ctx.put("retry", "yes"); + for(int i = 0; i < 10; ++i) + { + test(prx.amdAdd(33, 12, ctx) == 45); + test(interceptor.getLastOperation().equals("amdAdd")); + test(interceptor.getLastStatus()); + } + } out.println("ok"); out.print("testing user exception... "); out.flush(); @@ -159,6 +174,11 @@ public class Client extends test.TestHelper test(interceptor.getLastOperation().equals("amdBadSystemAdd")); test(interceptor.getLastStatus()); out.println("ok"); + + out.print("testing exceptions raised by the interceptor... "); + out.flush(); + testInterceptorExceptions(prx); + out.println("ok"); } public void run(String[] args) @@ -197,4 +217,63 @@ public class Client extends test.TestHelper runAmdTest(prx, interceptor, out); } } + + private class ExceptionPoint + { + public ExceptionPoint(String point, String exception) + { + this.point = point; + this.exception = exception; + } + public String point; + public String exception; + }; + + private void testInterceptorExceptions(MyObjectPrx prx) + { + java.util.List<ExceptionPoint> exceptions = new java.util.ArrayList<>(); + exceptions.add(new ExceptionPoint("raiseBeforeDispatch", "user")); + exceptions.add(new ExceptionPoint("raiseBeforeDispatch", "notExist")); + exceptions.add(new ExceptionPoint("raiseBeforeDispatch", "system")); + exceptions.add(new ExceptionPoint("raiseAfterDispatch", "user")); + exceptions.add(new ExceptionPoint("raiseAfterDispatch", "notExist")); + exceptions.add(new ExceptionPoint("raiseAfterDispatch", "system")); + for(ExceptionPoint e : exceptions) + { + java.util.Map<String, String> ctx = new java.util.HashMap<>(); + ctx.put(e.point, e.exception); + try + { + prx.ice_ping(ctx); + test(false); + } + catch(com.zeroc.Ice.UnknownUserException ex) + { + test(e.exception.equals("user")); + } + catch(com.zeroc.Ice.ObjectNotExistException ex) + { + test(e.exception.equals("notExist")); + } + catch(com.zeroc.Ice.UnknownException ex) + { + test(e.exception.equals("system")); // non-collocated + } + catch(MySystemException ex) + { + test(e.exception.equals("system")); // collocated + } + { + com.zeroc.Ice.ObjectPrx batch = prx.ice_batchOneway(); + batch.ice_ping(ctx); + batch.ice_ping(); + batch.ice_flushBatchRequests(); + + // Force the last batch request to be dispatched by the server thread using invocation timeouts + // This is required to preven threading issue with the test interceptor implementation which + // isn't thread safe + prx.ice_invocationTimeout(10000).ice_ping(); + } + } + } } diff --git a/java/test/src/main/java/test/Ice/interceptor/InterceptorI.java b/java/test/src/main/java/test/Ice/interceptor/InterceptorI.java index 2437717ecb1..afd5597f6b0 100644 --- a/java/test/src/main/java/test/Ice/interceptor/InterceptorI.java +++ b/java/test/src/main/java/test/Ice/interceptor/InterceptorI.java @@ -9,6 +9,7 @@ import java.util.concurrent.CompletionStage; import com.zeroc.Ice.OutputStream; import test.Ice.interceptor.Test.RetryException; +import test.Ice.interceptor.Test.InvalidInputException; class InterceptorI extends com.zeroc.Ice.DispatchInterceptor { @@ -30,6 +31,24 @@ class InterceptorI extends com.zeroc.Ice.DispatchInterceptor throws com.zeroc.Ice.UserException { com.zeroc.Ice.Current current = request.getCurrent(); + + String context = current.ctx.get("raiseBeforeDispatch"); + if(context != null) + { + if(context.equals("user")) + { + throw new InvalidInputException(); + } + else if(context.equals("notExist")) + { + throw new com.zeroc.Ice.ObjectNotExistException(); + } + else if(context.equals("system")) + { + throw new MySystemException(); + } + } + _lastOperation = current.operation; if(_lastOperation.equals("addWithRetry") || _lastOperation.equals("amdAddWithRetry")) @@ -51,9 +70,35 @@ class InterceptorI extends com.zeroc.Ice.DispatchInterceptor current.ctx.put("retry", "no"); } + else if(current.ctx.get("retry") != null && current.ctx.get("retry").equals("yes")) + { + // + // Retry the dispatch to ensure that abandoning the result of the dispatch + // works fine and is thread-safe + // + _servant.ice_dispatch(request); + _servant.ice_dispatch(request); + } CompletionStage<OutputStream> f = _servant.ice_dispatch(request); _lastStatus = f != null; + + context = current.ctx.get("raiseAfterDispatch"); + if(context != null) + { + if(context.equals("user")) + { + throw new InvalidInputException(); + } + else if(context.equals("notExist")) + { + throw new com.zeroc.Ice.ObjectNotExistException(); + } + else if(context.equals("system")) + { + throw new MySystemException(); + } + } return f; } diff --git a/java/test/src/main/java/test/Ice/metrics/AllTests.java b/java/test/src/main/java/test/Ice/metrics/AllTests.java index e72cb7586a9..c6035f6548e 100644 --- a/java/test/src/main/java/test/Ice/metrics/AllTests.java +++ b/java/test/src/main/java/test/Ice/metrics/AllTests.java @@ -911,7 +911,7 @@ public class AllTests out.flush(); props.put("IceMX.Metrics.View.Map.Invocation.GroupBy", "operation"); - props.put("IceMX.Metrics.View.Map.Invocation.Map.Remote.GroupBy", "localPort"); + props.put("IceMX.Metrics.View.Map.Invocation.Map.Remote.GroupBy", "id"); props.put("IceMX.Metrics.View.Map.Invocation.Map.Collocated.GroupBy", "id"); updateProps(clientProps, serverProps, props, "Invocation"); test(serverMetrics.getMetricsView("View").returnValue.get("Invocation").length == 0); @@ -1094,13 +1094,9 @@ public class AllTests if(!collocated) { im1 = (InvocationMetrics)map.get("fail"); - test(im1.current <= 1 && im1.total == 3 && im1.failures == 3 && im1.retry == 3 && im1.remotes.length == 6); - test(im1.remotes[0].current == 0 && im1.remotes[0].total == 1 && im1.remotes[0].failures == 1); - test(im1.remotes[1].current == 0 && im1.remotes[1].total == 1 && im1.remotes[1].failures == 1); - test(im1.remotes[2].current == 0 && im1.remotes[2].total == 1 && im1.remotes[2].failures == 1); - test(im1.remotes[3].current == 0 && im1.remotes[3].total == 1 && im1.remotes[3].failures == 1); - test(im1.remotes[4].current == 0 && im1.remotes[4].total == 1 && im1.remotes[4].failures == 1); - test(im1.remotes[5].current == 0 && im1.remotes[5].total == 1 && im1.remotes[5].failures == 1); + test(im1.current <= 1 && im1.total == 3 && im1.failures == 3 && im1.retry == 3 && im1.remotes.length == 1); + rim1 = (ChildInvocationMetrics)im1.remotes[0]; + test(rim1.current == 0 && rim1.total == 6 && rim1.failures == 6); checkFailure(clientMetrics, "Invocation", im1.id, "::Ice::ConnectionLostException", 3, out); } diff --git a/java/test/src/main/java/test/IceSSL/configuration/AllTests.java b/java/test/src/main/java/test/IceSSL/configuration/AllTests.java index 1f978a03e7d..bfa01f4e882 100644 --- a/java/test/src/main/java/test/IceSSL/configuration/AllTests.java +++ b/java/test/src/main/java/test/IceSSL/configuration/AllTests.java @@ -1385,6 +1385,10 @@ public class AllTests { server.ice_ping(); } + catch(com.zeroc.Ice.SecurityException ex) + { + // Expected on systems that disable DSA (EL8) + } catch(com.zeroc.Ice.LocalException ex) { ex.printStackTrace(); @@ -1511,7 +1515,7 @@ public class AllTests } catch(com.zeroc.Ice.ConnectionLostException ex) { - // Expected on systems that disable DSA + // Expected on systems that disable DSA (EL8) } catch(com.zeroc.Ice.LocalException ex) { |