summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDwayne Boone <dwayne@zeroc.com>2006-03-14 12:47:12 +0000
committerDwayne Boone <dwayne@zeroc.com>2006-03-14 12:47:12 +0000
commit4ec329c60555de5562c72df0e2fc583d591bf84d (patch)
tree86eb4af9aac33fc6277bed19d8936c4ffdbcd2d5
parentFixed http://www.zeroc.com/vbulletin/showthread.php?p=9533#post9533 (diff)
downloadice-4ec329c60555de5562c72df0e2fc583d591bf84d.tar.bz2
ice-4ec329c60555de5562c72df0e2fc583d591bf84d.tar.xz
ice-4ec329c60555de5562c72df0e2fc583d591bf84d.zip
Ported fix for bug 574.
-rwxr-xr-xcpp/src/slice2cs/Gen.cpp10
-rw-r--r--cpp/src/slice2java/Gen.cpp12
-rwxr-xr-xcpp/src/slice2vb/Gen.cpp10
-rw-r--r--java/CHANGES9
-rwxr-xr-xjava/allTests.py1
-rw-r--r--java/src/Ice/ConnectionI.java28
-rw-r--r--java/src/Ice/ObjectPrxHelperBase.java54
-rw-r--r--java/src/Ice/_ObjectDel.java10
-rw-r--r--java/src/Ice/_ObjectDelD.java10
-rw-r--r--java/src/Ice/_ObjectDelM.java20
-rw-r--r--java/src/IceInternal/FixedReference.java1
-rw-r--r--java/src/IceInternal/LocalExceptionWrapper.java49
-rw-r--r--java/src/IceInternal/Outgoing.java16
-rw-r--r--java/src/IceInternal/OutgoingAsync.java30
-rw-r--r--java/src/IceInternal/ProxyFactory.java115
-rw-r--r--java/src/IceInternal/RoutableReference.java24
-rw-r--r--java/test/Ice/build.xml5
-rw-r--r--java/test/Ice/retry/AllTests.java174
-rw-r--r--java/test/Ice/retry/Client.java67
-rw-r--r--java/test/Ice/retry/RetryI.java33
-rw-r--r--java/test/Ice/retry/Server.java66
-rw-r--r--java/test/Ice/retry/Test.ice (renamed from java/src/IceInternal/NonRepeatable.java)25
-rw-r--r--java/test/Ice/retry/build.xml58
-rwxr-xr-xjava/test/Ice/retry/run.py29
-rwxr-xr-xpy/allTests.py1
-rw-r--r--py/test/Ice/retry/AllTests.py114
-rw-r--r--py/test/Ice/retry/Client.py68
-rw-r--r--py/test/Ice/retry/Server.py61
-rw-r--r--py/test/Ice/retry/Test.ice24
-rw-r--r--py/test/Ice/retry/TestI.py20
-rwxr-xr-xpy/test/Ice/retry/run.py26
31 files changed, 1014 insertions, 156 deletions
diff --git a/cpp/src/slice2cs/Gen.cpp b/cpp/src/slice2cs/Gen.cpp
index 753070d6296..87d9abb29ed 100755
--- a/cpp/src/slice2cs/Gen.cpp
+++ b/cpp/src/slice2cs/Gen.cpp
@@ -3349,15 +3349,15 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p)
_out << nl << "return;";
}
_out << eb;
- _out << nl << "catch(IceInternal.NonRepeatable ex__)";
+ _out << nl << "catch(IceInternal.LocalExceptionWrapper ex__)";
_out << sb;
if(op->mode() == Operation::Idempotent || op->mode() == Operation::Nonmutating)
{
- _out << nl << "cnt__ = handleException__(ex__.get(), cnt__);";
+ _out << nl << "cnt__ = handleExceptionWrapperRelaxed__(ex__, cnt__);";
}
else
{
- _out << nl << "rethrowException__(ex__.get());";
+ _out << nl << "handleExceptionWrapper__(ex__);";
}
_out << eb;
_out << nl << "catch(Ice.LocalException ex__)";
@@ -4020,7 +4020,7 @@ Slice::Gen::DelegateMVisitor::visitClassDefStart(const ClassDefPtr& p)
_out << eb;
_out << nl << "catch(Ice.LocalException ex__)";
_out << sb;
- _out << nl << "throw new IceInternal.NonRepeatable(ex__);";
+ _out << nl << "throw new IceInternal.LocalExceptionWrapper(ex__, false);";
_out << eb;
_out << eb;
_out << nl << "finally";
@@ -4125,7 +4125,7 @@ Slice::Gen::DelegateDVisitor::visitClassDefStart(const ClassDefPtr& p)
_out << eb;
_out << nl << "catch(Ice.LocalException ex__)";
_out << sb;
- _out << nl << "throw new IceInternal.NonRepeatable(ex__);";
+ _out << nl << "throw new IceInternal.LocalExceptionWrapper(ex__, false);";
_out << eb;
_out << nl << "finally";
_out << sb;
diff --git a/cpp/src/slice2java/Gen.cpp b/cpp/src/slice2java/Gen.cpp
index 648dd82c3b8..bbee749c47f 100644
--- a/cpp/src/slice2java/Gen.cpp
+++ b/cpp/src/slice2java/Gen.cpp
@@ -242,7 +242,7 @@ Slice::JavaVisitor::writeDelegateThrowsClause(const string& package, const Excep
out.inc();
out << nl << "throws ";
out.useCurrentPosAsIndent();
- out << "IceInternal.NonRepeatable";
+ out << "IceInternal.LocalExceptionWrapper";
ExceptionList::const_iterator r;
for(r = throws.begin(); r != throws.end(); ++r)
@@ -3090,15 +3090,15 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p)
out << nl << "return;";
}
out << eb;
- out << nl << "catch(IceInternal.NonRepeatable __ex)";
+ out << nl << "catch(IceInternal.LocalExceptionWrapper __ex)";
out << sb;
if(op->mode() == Operation::Idempotent || op->mode() == Operation::Nonmutating)
{
- out << nl << "__cnt = __handleException(__ex.get(), __cnt);";
+ out << nl << "__cnt = __handleExceptionWrapperRelaxed(__ex, __cnt);";
}
else
{
- out << nl << "__rethrowException(__ex.get());";
+ out << nl << "__handleExceptionWrapper(__ex);";
}
out << eb;
out << nl << "catch(Ice.LocalException __ex)";
@@ -3893,7 +3893,7 @@ Slice::Gen::DelegateMVisitor::visitClassDefStart(const ClassDefPtr& p)
out << eb;
out << nl << "catch(Ice.LocalException __ex)";
out << sb;
- out << nl << "throw new IceInternal.NonRepeatable(__ex);";
+ out << nl << "throw new IceInternal.LocalExceptionWrapper(__ex, false);";
out << eb;
out << eb;
out << nl << "finally";
@@ -4003,7 +4003,7 @@ Slice::Gen::DelegateDVisitor::visitClassDefStart(const ClassDefPtr& p)
out << eb;
out << nl << "catch(Ice.LocalException __ex)";
out << sb;
- out << nl << "throw new IceInternal.NonRepeatable(__ex);";
+ out << nl << "throw new IceInternal.LocalExceptionWrapper(__ex, false);";
out << eb;
out << eb;
out << nl << "finally";
diff --git a/cpp/src/slice2vb/Gen.cpp b/cpp/src/slice2vb/Gen.cpp
index e9007cb2130..280cb8ab97d 100755
--- a/cpp/src/slice2vb/Gen.cpp
+++ b/cpp/src/slice2vb/Gen.cpp
@@ -3691,15 +3691,15 @@ Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p)
_out << nl << "Return";
}
_out.dec();
- _out << nl << "Catch ex__ As IceInternal.NonRepeatable";
+ _out << nl << "Catch ex__ As IceInternal.LocalExceptionWrapper";
_out.inc();
if(op->mode() == Operation::Idempotent || op->mode() == Operation::Nonmutating)
{
- _out << nl << "cnt__ = handleException__(ex__.get(), cnt__)";
+ _out << nl << "cnt__ = handleExceptionWrapperRelaxed__(ex__, cnt__)";
}
else
{
- _out << nl << "rethrowException__(ex__.get())";
+ _out << nl << "handleExceptionWrapper__(ex__)";
}
_out.dec();
_out << nl << "Catch ex__ As Ice.LocalException";
@@ -4464,7 +4464,7 @@ Slice::Gen::DelegateMVisitor::visitClassDefStart(const ClassDefPtr& p)
_out.dec();
_out << nl << "Catch ex__ As Ice.LocalException";
_out.inc();
- _out << nl << "throw New IceInternal.NonRepeatable(ex__)";
+ _out << nl << "throw New IceInternal.LocalExceptionWrapper(ex__, false)";
_out.dec();
_out << nl << "End Try";
_out.dec();
@@ -4583,7 +4583,7 @@ Slice::Gen::DelegateDVisitor::visitClassDefStart(const ClassDefPtr& p)
_out.dec();
_out << nl << "Catch ex__ As Ice.LocalException";
_out.inc();
- _out << nl << "Throw New IceInternal.NonRepeatable(ex__)";
+ _out << nl << "Throw New IceInternal.LocalExceptionWrapper(ex__, false)";
_out.dec();
_out << nl << "Finally";
_out.inc();
diff --git a/java/CHANGES b/java/CHANGES
index a5256e0142a..79795af92bb 100644
--- a/java/CHANGES
+++ b/java/CHANGES
@@ -1,6 +1,15 @@
Changes since version 3.0.1
---------------------------
+- Performance improvements if an AMI callback object is reused with
+ the same proxy.
+
+- If several proxies share the same connection, and an operation call
+ on one of the proxies causes a failure and the shared connection to
+ be closed, then subsequent calls on the other proxies will try to
+ establish a new connection instead of throwing an exception, even if
+ retries are disabled.
+
- Fixed bug in identityToString() and proxyToString() that could
cause incorrect string values to be returned for identities
containing characters outside the ASCII range.
diff --git a/java/allTests.py b/java/allTests.py
index 9f580b6c661..a2dec50ccd7 100755
--- a/java/allTests.py
+++ b/java/allTests.py
@@ -68,6 +68,7 @@ tests = [ \
"Ice/checksum", \
"Ice/package", \
"Ice/stream", \
+ "Ice/retry", \
"Freeze/dbmap", \
"Freeze/complex", \
"Freeze/evictor", \
diff --git a/java/src/Ice/ConnectionI.java b/java/src/Ice/ConnectionI.java
index c65d91082df..1446568273f 100644
--- a/java/src/Ice/ConnectionI.java
+++ b/java/src/Ice/ConnectionI.java
@@ -319,6 +319,16 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
}
public synchronized void
+ throwException()
+ {
+ if(_exception != null)
+ {
+ assert(_state >= StateClosing);
+ throw _exception;
+ }
+ }
+
+ public synchronized void
waitUntilHolding()
{
while(_state < StateHolding || _dispatchCount > 0)
@@ -495,6 +505,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
public void
sendRequest(IceInternal.BasicStream os, IceInternal.Outgoing out, boolean compress)
+ throws IceInternal.LocalExceptionWrapper
{
int requestId = 0;
IceInternal.BasicStream stream = null;
@@ -505,7 +516,12 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
if(_exception != null)
{
- throw _exception;
+ //
+ // If the connection is closed before we even have a chance
+ // to send our request, we always try to send the request
+ // again.
+ //
+ throw new IceInternal.LocalExceptionWrapper(_exception, true);
}
assert(_state > StateNotValidated);
@@ -605,6 +621,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
public void
sendAsyncRequest(IceInternal.BasicStream os, IceInternal.OutgoingAsync out, boolean compress)
+ throws IceInternal.LocalExceptionWrapper
{
int requestId = 0;
IceInternal.BasicStream stream = null;
@@ -615,7 +632,12 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
if(_exception != null)
{
- throw _exception;
+ //
+ // If the connection is closed before we even have a chance
+ // to send our request, we always try to send the request
+ // again.
+ //
+ throw new IceInternal.LocalExceptionWrapper(_exception, true);
}
assert(_state > StateNotValidated);
@@ -2383,7 +2405,7 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne
public IceInternal.Outgoing
getOutgoing(IceInternal.Reference reference, String operation, OperationMode mode, java.util.Map context,
boolean compress)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing out = null;
diff --git a/java/src/Ice/ObjectPrxHelperBase.java b/java/src/Ice/ObjectPrxHelperBase.java
index 125e227438e..98fd2b40044 100644
--- a/java/src/Ice/ObjectPrxHelperBase.java
+++ b/java/src/Ice/ObjectPrxHelperBase.java
@@ -56,9 +56,9 @@ public class ObjectPrxHelperBase implements ObjectPrx
_ObjectDel __del = __getDelegate();
return __del.ice_isA(__id, __context);
}
- catch(IceInternal.NonRepeatable __ex)
+ catch(IceInternal.LocalExceptionWrapper __ex)
{
- __cnt = __handleException(__ex.get(), __cnt);
+ __cnt = __handleExceptionWrapperRelaxed(__ex, __cnt);
}
catch(LocalException __ex)
{
@@ -86,9 +86,9 @@ public class ObjectPrxHelperBase implements ObjectPrx
__del.ice_ping(__context);
return;
}
- catch(IceInternal.NonRepeatable __ex)
+ catch(IceInternal.LocalExceptionWrapper __ex)
{
- __cnt = __handleException(__ex.get(), __cnt);
+ __cnt = __handleExceptionWrapperRelaxed(__ex, __cnt);
}
catch(LocalException __ex)
{
@@ -115,9 +115,9 @@ public class ObjectPrxHelperBase implements ObjectPrx
_ObjectDel __del = __getDelegate();
return __del.ice_ids(__context);
}
- catch(IceInternal.NonRepeatable __ex)
+ catch(IceInternal.LocalExceptionWrapper __ex)
{
- __cnt = __handleException(__ex.get(), __cnt);
+ __cnt = __handleExceptionWrapperRelaxed(__ex, __cnt);
}
catch(LocalException __ex)
{
@@ -144,9 +144,9 @@ public class ObjectPrxHelperBase implements ObjectPrx
_ObjectDel __del = __getDelegate();
return __del.ice_id(__context);
}
- catch(IceInternal.NonRepeatable __ex)
+ catch(IceInternal.LocalExceptionWrapper __ex)
{
- __cnt = __handleException(__ex.get(), __cnt);
+ __cnt = __handleExceptionWrapperRelaxed(__ex, __cnt);
}
catch(LocalException __ex)
{
@@ -173,15 +173,15 @@ public class ObjectPrxHelperBase implements ObjectPrx
_ObjectDel __del = __getDelegate();
return __del.ice_invoke(operation, mode, inParams, outParams, context);
}
- catch(IceInternal.NonRepeatable __ex)
+ catch(IceInternal.LocalExceptionWrapper __ex)
{
if(mode == OperationMode.Nonmutating || mode == OperationMode.Idempotent)
{
- __cnt = __handleException(__ex.get(), __cnt);
+ __cnt = __handleExceptionWrapperRelaxed(__ex, __cnt);
}
else
{
- __rethrowException(__ex.get());
+ __handleExceptionWrapper(__ex);
}
}
catch(LocalException __ex)
@@ -723,11 +723,35 @@ public class ObjectPrxHelperBase implements ObjectPrx
}
}
- public final synchronized void
- __rethrowException(LocalException ex)
+ public final void
+ __handleExceptionWrapper(IceInternal.LocalExceptionWrapper ex)
{
- _delegate = null;
- throw ex;
+ synchronized(this)
+ {
+ _delegate = null;
+ }
+
+ if(!ex.retry())
+ {
+ throw ex.get();
+ }
+ }
+
+ public final int
+ __handleExceptionWrapperRelaxed(IceInternal.LocalExceptionWrapper ex, int cnt)
+ {
+ if(!ex.retry())
+ {
+ return __handleException(ex.get(), cnt);
+ }
+ else
+ {
+ synchronized(this)
+ {
+ _delegate = null;
+ }
+ return cnt;
+ }
}
public final void
diff --git a/java/src/Ice/_ObjectDel.java b/java/src/Ice/_ObjectDel.java
index 5adb5143e23..f4c208f7fb1 100644
--- a/java/src/Ice/_ObjectDel.java
+++ b/java/src/Ice/_ObjectDel.java
@@ -12,20 +12,20 @@ package Ice;
public interface _ObjectDel
{
boolean ice_isA(String id, java.util.Map context)
- throws IceInternal.NonRepeatable;
+ throws IceInternal.LocalExceptionWrapper;
void ice_ping(java.util.Map context)
- throws IceInternal.NonRepeatable;
+ throws IceInternal.LocalExceptionWrapper;
String[] ice_ids(java.util.Map context)
- throws IceInternal.NonRepeatable;
+ throws IceInternal.LocalExceptionWrapper;
String ice_id(java.util.Map context)
- throws IceInternal.NonRepeatable;
+ throws IceInternal.LocalExceptionWrapper;
boolean ice_invoke(String operation, Ice.OperationMode mode, byte[] inParams, ByteSeqHolder outParams,
java.util.Map context)
- throws IceInternal.NonRepeatable;
+ throws IceInternal.LocalExceptionWrapper;
Connection ice_connection();
}
diff --git a/java/src/Ice/_ObjectDelD.java b/java/src/Ice/_ObjectDelD.java
index 20fd114beb1..40058a4b9f8 100644
--- a/java/src/Ice/_ObjectDelD.java
+++ b/java/src/Ice/_ObjectDelD.java
@@ -13,7 +13,7 @@ public class _ObjectDelD implements _ObjectDel
{
public boolean
ice_isA(String __id, java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
Current __current = new Current();
__initCurrent(__current, "ice_isA", OperationMode.Nonmutating, __context);
@@ -33,7 +33,7 @@ public class _ObjectDelD implements _ObjectDel
public void
ice_ping(java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
Current __current = new Current();
__initCurrent(__current, "ice_ping", OperationMode.Nonmutating, __context);
@@ -54,7 +54,7 @@ public class _ObjectDelD implements _ObjectDel
public String[]
ice_ids(java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
Current __current = new Current();
__initCurrent(__current, "ice_ids", OperationMode.Nonmutating, __context);
@@ -74,7 +74,7 @@ public class _ObjectDelD implements _ObjectDel
public String
ice_id(java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
Current __current = new Current();
__initCurrent(__current, "ice_id", OperationMode.Nonmutating, __context);
@@ -95,7 +95,7 @@ public class _ObjectDelD implements _ObjectDel
public boolean
ice_invoke(String operation, Ice.OperationMode mode, byte[] inParams, ByteSeqHolder outParams,
java.util.Map context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
throw new CollocationOptimizationException();
}
diff --git a/java/src/Ice/_ObjectDelM.java b/java/src/Ice/_ObjectDelM.java
index c6301ce909d..6a5501e170c 100644
--- a/java/src/Ice/_ObjectDelM.java
+++ b/java/src/Ice/_ObjectDelM.java
@@ -13,7 +13,7 @@ public class _ObjectDelM implements _ObjectDel
{
public boolean
ice_isA(String __id, java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_isA", OperationMode.Nonmutating,
__context, __compress);
@@ -47,7 +47,7 @@ public class _ObjectDelM implements _ObjectDel
}
catch(LocalException __ex)
{
- throw new IceInternal.NonRepeatable(__ex);
+ throw new IceInternal.LocalExceptionWrapper(__ex, false);
}
}
finally
@@ -58,7 +58,7 @@ public class _ObjectDelM implements _ObjectDel
public void
ice_ping(java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_ping", OperationMode.Nonmutating,
__context, __compress);
@@ -82,7 +82,7 @@ public class _ObjectDelM implements _ObjectDel
}
catch(LocalException __ex)
{
- throw new IceInternal.NonRepeatable(__ex);
+ throw new IceInternal.LocalExceptionWrapper(__ex, false);
}
}
finally
@@ -93,7 +93,7 @@ public class _ObjectDelM implements _ObjectDel
public String[]
ice_ids(java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_ids", OperationMode.Nonmutating,
__context, __compress);
@@ -118,7 +118,7 @@ public class _ObjectDelM implements _ObjectDel
}
catch(LocalException __ex)
{
- throw new IceInternal.NonRepeatable(__ex);
+ throw new IceInternal.LocalExceptionWrapper(__ex, false);
}
}
finally
@@ -129,7 +129,7 @@ public class _ObjectDelM implements _ObjectDel
public String
ice_id(java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing __og = __connection.getOutgoing(__reference, "ice_id", OperationMode.Nonmutating,
__context, __compress);
@@ -154,7 +154,7 @@ public class _ObjectDelM implements _ObjectDel
}
catch(LocalException __ex)
{
- throw new IceInternal.NonRepeatable(__ex);
+ throw new IceInternal.LocalExceptionWrapper(__ex, false);
}
}
finally
@@ -165,7 +165,7 @@ public class _ObjectDelM implements _ObjectDel
public boolean
ice_invoke(String operation, OperationMode mode, byte[] inParams, ByteSeqHolder outParams, java.util.Map __context)
- throws IceInternal.NonRepeatable
+ throws IceInternal.LocalExceptionWrapper
{
IceInternal.Outgoing __og = __connection.getOutgoing(__reference, operation, mode, __context, __compress);
try
@@ -196,7 +196,7 @@ public class _ObjectDelM implements _ObjectDel
}
catch(LocalException __ex)
{
- throw new IceInternal.NonRepeatable(__ex);
+ throw new IceInternal.LocalExceptionWrapper(__ex, false);
}
}
return ok;
diff --git a/java/src/IceInternal/FixedReference.java b/java/src/IceInternal/FixedReference.java
index 445fd725ca3..b3d77f7a5b2 100644
--- a/java/src/IceInternal/FixedReference.java
+++ b/java/src/IceInternal/FixedReference.java
@@ -174,6 +174,7 @@ public class FixedReference extends Reference
Ice.ConnectionI connection = filteredConns[0];
assert(connection != null);
+ connection.throwException(); // Throw in case our connection is already destroyed.
compress.value = connection.endpoint().compress();
return connection;
diff --git a/java/src/IceInternal/LocalExceptionWrapper.java b/java/src/IceInternal/LocalExceptionWrapper.java
new file mode 100644
index 00000000000..2d60f8d219a
--- /dev/null
+++ b/java/src/IceInternal/LocalExceptionWrapper.java
@@ -0,0 +1,49 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceInternal;
+
+public class LocalExceptionWrapper extends Exception
+{
+ public
+ LocalExceptionWrapper(Ice.LocalException ex, boolean retry)
+ {
+ _ex = ex;
+ _retry = retry;
+ }
+
+ public
+ LocalExceptionWrapper(IceInternal.LocalExceptionWrapper ex)
+ {
+ _ex = ex.get();
+ _retry = ex._retry;
+ }
+
+ public Ice.LocalException
+ get()
+ {
+ return _ex;
+ }
+
+ //
+ // If true, always repeat the request. Don't take retry settings
+ // or "at-most-once" guarantees into account.
+ //
+ // If false, only repeat the request if the retry settings allow
+ // to do so, and if "at-most-once" does not need to be guaranteed.
+ //
+ public boolean
+ retry()
+ {
+ return _retry;
+ }
+
+ private Ice.LocalException _ex;
+ private boolean _retry;
+}
diff --git a/java/src/IceInternal/Outgoing.java b/java/src/IceInternal/Outgoing.java
index 6640129de61..c32f6055829 100644
--- a/java/src/IceInternal/Outgoing.java
+++ b/java/src/IceInternal/Outgoing.java
@@ -14,7 +14,7 @@ public final class Outgoing
public
Outgoing(Ice.ConnectionI connection, Reference ref, String operation, Ice.OperationMode mode,
java.util.Map context, boolean compress)
- throws NonRepeatable
+ throws LocalExceptionWrapper
{
_connection = connection;
_reference = ref;
@@ -31,7 +31,7 @@ public final class Outgoing
//
public void
reset(Reference ref, String operation, Ice.OperationMode mode, java.util.Map context, boolean compress)
- throws NonRepeatable
+ throws LocalExceptionWrapper
{
_reference = ref;
_state = StateUnsent;
@@ -51,7 +51,7 @@ public final class Outgoing
// Returns true if ok, false if user exception.
public boolean
invoke()
- throws NonRepeatable
+ throws LocalExceptionWrapper
{
assert(_state == StateUnsent);
@@ -165,11 +165,11 @@ public final class Outgoing
}
//
- // Throw the exception wrapped in a NonRepeatable, to
+ // Throw the exception wrapped in a LocalExceptionWrapper, to
// indicate that the request cannot be resent without
// potentially violating the "at-most-once" principle.
//
- throw new NonRepeatable(_exception);
+ throw new LocalExceptionWrapper(_exception, false);
}
if(_state == StateUserException)
@@ -216,7 +216,7 @@ public final class Outgoing
public void
abort(Ice.LocalException ex)
- throws NonRepeatable
+ throws LocalExceptionWrapper
{
assert(_state == StateUnsent);
@@ -236,7 +236,7 @@ public final class Outgoing
// be aborted, but all other requests in the batch as
// well.
//
- throw new NonRepeatable(ex);
+ throw new LocalExceptionWrapper(ex, false);
}
throw ex;
@@ -413,7 +413,7 @@ public final class Outgoing
private void
writeHeader(String operation, Ice.OperationMode mode, java.util.Map context)
- throws NonRepeatable
+ throws LocalExceptionWrapper
{
switch(_reference.getMode())
{
diff --git a/java/src/IceInternal/OutgoingAsync.java b/java/src/IceInternal/OutgoingAsync.java
index 15a1c158e16..f83b5cbc9ea 100644
--- a/java/src/IceInternal/OutgoingAsync.java
+++ b/java/src/IceInternal/OutgoingAsync.java
@@ -173,7 +173,7 @@ public abstract class OutgoingAsync
{
synchronized(_monitor)
{
- if(_reference != null)
+ if(__os != null) // Don't retry if cleanup() was already called.
{
boolean doRetry = false;
@@ -264,7 +264,7 @@ public abstract class OutgoingAsync
//
// We must first wait for other requests to finish.
//
- while(_reference != null)
+ while(__os != null)
{
try
{
@@ -279,10 +279,19 @@ public abstract class OutgoingAsync
// Can't call async via a oneway proxy.
//
((Ice.ObjectPrxHelperBase)prx).__checkTwowayOnly(operation);
+
+ Reference ref = ((Ice.ObjectPrxHelperBase)prx).__reference();
+
+ //
+ // Optimization: Don't update the connection if it is not
+ // necessary.
+ //
+ if(_connection == null || _reference == null || !_reference.equals(ref))
+ {
+ _connection = ref.getConnection(_compress);
+ }
- _reference = ((Ice.ObjectPrxHelperBase)prx).__reference();
- assert(_connection == null);
- _connection = _reference.getConnection(_compress);
+ _reference = ref;
_cnt = 0;
_mode = mode;
assert(__is == null);
@@ -394,6 +403,13 @@ public abstract class OutgoingAsync
//
return;
}
+ catch(LocalExceptionWrapper ex)
+ {
+ if(!ex.retry())
+ {
+ throw ex.get();
+ }
+ }
catch(Ice.LocalException ex)
{
ProxyFactory proxyFactory = _reference.getInstance().proxyFactory();
@@ -422,7 +438,7 @@ public abstract class OutgoingAsync
private final void
warning(java.lang.Exception ex)
{
- if(_reference != null) // Don't print anything if cleanup() was already called.
+ if(__os != null) // Don't print anything if cleanup() was already called.
{
if(_reference.getInstance().properties().getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0)
{
@@ -441,8 +457,6 @@ public abstract class OutgoingAsync
private final void
cleanup()
{
- _reference = null;
- _connection = null;
__is = null;
__os = null;
diff --git a/java/src/IceInternal/ProxyFactory.java b/java/src/IceInternal/ProxyFactory.java
index c3a8132395a..1a2e1731090 100644
--- a/java/src/IceInternal/ProxyFactory.java
+++ b/java/src/IceInternal/ProxyFactory.java
@@ -105,86 +105,77 @@ public final class ProxyFactory
throw ex;
}
- //
- // There is no point in retrying an operation that resulted in a
- // MarshalException. This must have been raised locally (because if
- // it happened in a server it would result in an UnknownLocalException
- // instead), which means there was a problem in this process that will
- // not change if we try again.
- //
- // The most likely cause for a MarshalException is exceeding the
- // maximum message size, which is represented by the the subclass
- // MemoryLimitException. For example, a client can attempt to send a
- // message that exceeds the maximum memory size, or accumulate enough
- // batch requests without flushing that the maximum size is reached.
- //
- // This latter case is especially problematic, because if we were to
- // retry a batch request after a MarshalException, we would in fact
- // silently discard the accumulated requests and allow new batch
- // requests to accumulate. If the subsequent batched requests do not
- // exceed the maximum message size, it appears to the client that all
- // of the batched requests were accepted, when in reality only the
- // last few are actually sent.
- //
- if(ex instanceof Ice.MarshalException)
- {
- throw ex;
- }
+ //
+ // There is no point in retrying an operation that resulted in a
+ // MarshalException. This must have been raised locally (because
+ // if it happened in a server it would result in an
+ // UnknownLocalException instead), which means there was a problem
+ // in this process that will not change if we try again.
+ //
+ // The most likely cause for a MarshalException is exceeding the
+ // maximum message size, which is represented by the the subclass
+ // MemoryLimitException. For example, a client can attempt to send
+ // a message that exceeds the maximum memory size, or accumulate
+ // enough batch requests without flushing that the maximum size is
+ // reached.
+ //
+ // This latter case is especially problematic, because if we were
+ // to retry a batch request after a MarshalException, we would in
+ // fact silently discard the accumulated requests and allow new
+ // batch requests to accumulate. If the subsequent batched
+ // requests do not exceed the maximum message size, it appears to
+ // the client that all of the batched requests were accepted, when
+ // in reality only the last few are actually sent.
+ //
+ if(ex instanceof Ice.MarshalException)
+ {
+ throw ex;
+ }
- ++cnt;
+ ++cnt;
+ assert(cnt > 0);
TraceLevels traceLevels = _instance.traceLevels();
Ice.Logger logger = _instance.logger();
- //
- // Instance components may be null if Communicator has been destroyed.
- //
- if(traceLevels != null && logger != null)
+ if(cnt > _retryIntervals.length)
{
- if(cnt > _retryIntervals.length)
- {
- if(traceLevels.retry >= 1)
- {
- String s = "cannot retry operation call because retry limit has been exceeded\n" + ex.toString();
- logger.trace(traceLevels.retryCat, s);
- }
- throw ex;
- }
-
if(traceLevels.retry >= 1)
{
- String s = "re-trying operation call";
- if(cnt > 0 && _retryIntervals[cnt - 1] > 0)
- {
- s += " in " + _retryIntervals[cnt - 1] + "ms";
- }
- s += " because of exception\n" + ex;
+ String s = "cannot retry operation call because retry limit has been exceeded\n" + ex.toString();
logger.trace(traceLevels.retryCat, s);
}
+ throw ex;
+ }
+
+ int interval = _retryIntervals[cnt - 1];
- if(cnt > 0)
+ if(traceLevels.retry >= 1)
+ {
+ String s = "re-trying operation call";
+ if(interval > 0)
{
- //
- // Sleep before retrying.
- //
- try
- {
- Thread.currentThread().sleep(_retryIntervals[cnt - 1]);
- }
- catch(InterruptedException ex1)
- {
- }
+ s += " in " + interval + "ms";
}
-
- return cnt;
+ s += " because of exception\n" + ex;
+ logger.trace(traceLevels.retryCat, s);
}
- else
+
+ if(cnt > 0)
{
//
- // Impossible to retry after Communicator has been destroyed.
+ // Sleep before retrying.
//
- throw ex;
+ try
+ {
+ Thread.currentThread().sleep(interval);
+ }
+ catch(InterruptedException ex1)
+ {
+ }
}
+
+ return cnt;
}
//
diff --git a/java/src/IceInternal/RoutableReference.java b/java/src/IceInternal/RoutableReference.java
index e17e6b873d7..b2085dc0859 100644
--- a/java/src/IceInternal/RoutableReference.java
+++ b/java/src/IceInternal/RoutableReference.java
@@ -237,15 +237,21 @@ public abstract class RoutableReference extends Reference
//
switch(getEndpointSelection().value())
{
- case Ice.EndpointSelectionType._Random:
- java.util.Collections.shuffle(endpoints);
- break;
- case Ice.EndpointSelectionType._Ordered:
- // Nothing to do.
- break;
- default:
- assert(false);
- break;
+ case Ice.EndpointSelectionType._Random:
+ {
+ java.util.Collections.shuffle(endpoints);
+ break;
+ }
+ case Ice.EndpointSelectionType._Ordered:
+ {
+ // Nothing to do.
+ break;
+ }
+ default:
+ {
+ assert(false);
+ break;
+ }
}
//
diff --git a/java/test/Ice/build.xml b/java/test/Ice/build.xml
index e4a2a76728e..57719374a06 100644
--- a/java/test/Ice/build.xml
+++ b/java/test/Ice/build.xml
@@ -29,11 +29,13 @@
<ant dir="translator"/>
<ant dir="checksum"/>
<ant dir="package"/>
- <ant dir="stream"/>
+ <ant dir="stream"/>
+ <ant dir="retry"/>
</target>
<target name="clean">
<ant dir="adapterDeactivation" target="clean"/>
+ <ant dir="binding" target="clean"/>
<ant dir="exceptions" target="clean"/>
<ant dir="exceptionsAMD" target="clean"/>
<ant dir="facets" target="clean"/>
@@ -50,6 +52,7 @@
<ant dir="checksum" target="clean"/>
<ant dir="package" target="clean"/>
<ant dir="stream" target="clean"/>
+ <ant dir="retry" target="clean"/>
</target>
</project>
diff --git a/java/test/Ice/retry/AllTests.java b/java/test/Ice/retry/AllTests.java
new file mode 100644
index 00000000000..f9b764ae2ac
--- /dev/null
+++ b/java/test/Ice/retry/AllTests.java
@@ -0,0 +1,174 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice-E is licensed to you under the terms described in the
+// ICEE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+public class AllTests
+{
+ private static void
+ test(boolean b)
+ {
+ if(!b)
+ {
+ throw new RuntimeException();
+ }
+ }
+
+ private static class Callback
+ {
+ Callback()
+ {
+ _called = false;
+ }
+
+ public synchronized boolean
+ check()
+ {
+ while(!_called)
+ {
+ try
+ {
+ wait(5000);
+ }
+ catch(InterruptedException ex)
+ {
+ continue;
+ }
+
+ if(!_called)
+ {
+ return false; // Must be timeout.
+ }
+ }
+
+ _called = false;
+ return true;
+ }
+
+ public synchronized void
+ called()
+ {
+ assert(!_called);
+ _called = true;
+ notify();
+ }
+
+ private boolean _called;
+ }
+
+ private static class AMIRegular extends Test.AMI_Retry_op
+ {
+ public void
+ ice_response()
+ {
+ callback.called();
+ }
+
+ public void
+ ice_exception(Ice.LocalException ex)
+ {
+ test(false);
+ }
+
+ public boolean
+ check()
+ {
+ return callback.check();
+ }
+
+ private Callback callback = new Callback();
+ }
+
+ private static class AMIException extends Test.AMI_Retry_op
+ {
+ public void
+ ice_response()
+ {
+ test(false);
+ }
+
+ public void
+ ice_exception(Ice.LocalException ex)
+ {
+ test(ex instanceof Ice.ConnectionLostException);
+ callback.called();
+ }
+
+ public boolean
+ check()
+ {
+ return callback.check();
+ }
+
+ private Callback callback = new Callback();
+ }
+
+ public static Test.RetryPrx
+ allTests(Ice.Communicator communicator, java.io.PrintStream out)
+ {
+ out.print("testing stringToProxy... ");
+ out.flush();
+ String ref = "retry:default -p 12010 -t 10000";
+ Ice.ObjectPrx base1 = communicator.stringToProxy(ref);
+ test(base1 != null);
+ Ice.ObjectPrx base2 = communicator.stringToProxy(ref);
+ test(base2 != null);
+ out.println("ok");
+
+ out.print("testing checked cast... ");
+ out.flush();
+ Test.RetryPrx retry1 = Test.RetryPrxHelper.checkedCast(base1);
+ test(retry1 != null);
+ test(retry1.equals(base1));
+ Test.RetryPrx retry2 = Test.RetryPrxHelper.checkedCast(base2);
+ test(retry2 != null);
+ test(retry2.equals(base2));
+ out.println("ok");
+
+ out.print("calling regular operation with first proxy... ");
+ out.flush();
+ retry1.op(false);
+ out.println("ok");
+
+ out.print("calling operation to kill connection with second proxy... ");
+ out.flush();
+ try
+ {
+ retry2.op(true);
+ test(false);
+ }
+ catch(Ice.ConnectionLostException ex)
+ {
+ out.println("ok");
+ }
+
+ out.print("calling regular operation with first proxy again... ");
+ out.flush();
+ retry1.op(false);
+ out.println("ok");
+
+ AMIRegular cb1 = new AMIRegular();
+ AMIException cb2 = new AMIException();
+
+ out.print("calling regular AMI operation with first proxy... ");
+ retry1.op_async(cb1, false);
+ test(cb1.check());
+ out.println("ok");
+
+ out.print("calling AMI operation to kill connection with second proxy... ");
+ retry2.op_async(cb2, true);
+ test(cb2.check());
+ out.println("ok");
+
+ out.print("calling regular AMI operation with first proxy again... ");
+ retry1.op_async(cb1, false);
+ test(cb1.check());
+ out.println("ok");
+
+ return retry1;
+ }
+}
diff --git a/java/test/Ice/retry/Client.java b/java/test/Ice/retry/Client.java
new file mode 100644
index 00000000000..49b9f330b9a
--- /dev/null
+++ b/java/test/Ice/retry/Client.java
@@ -0,0 +1,67 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice-E is licensed to you under the terms described in the
+// ICEE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+public class Client
+{
+ public static int
+ run(String[] args, Ice.Communicator communicator, java.io.PrintStream out)
+ {
+ Test.RetryPrx retry = AllTests.allTests(communicator, out);
+ retry.shutdown();
+ return 0;
+ }
+
+ public static void
+ main(String[] args)
+ {
+ int status = 0;
+ Ice.Communicator communicator = null;
+
+ try
+ {
+ Ice.StringSeqHolder argsH = new Ice.StringSeqHolder(args);
+ Ice.Properties properties = Ice.Util.getDefaultProperties(argsH);
+
+ //
+ // For this test, we want to disable retries.
+ //
+ properties.setProperty("Ice.RetryIntervals", "-1");
+
+ communicator = Ice.Util.initialize(argsH);
+
+ //
+ // We don't want connection warnings because of the timeout test.
+ //
+ properties.setProperty("Ice.Warn.Connections", "0");
+
+ status = run(argsH.value, communicator, System.out);
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ status = 1;
+ }
+
+ if(communicator != null)
+ {
+ try
+ {
+ communicator.destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ status = 1;
+ }
+ }
+
+ System.gc();
+ System.exit(status);
+ }
+}
diff --git a/java/test/Ice/retry/RetryI.java b/java/test/Ice/retry/RetryI.java
new file mode 100644
index 00000000000..69e9fbdf461
--- /dev/null
+++ b/java/test/Ice/retry/RetryI.java
@@ -0,0 +1,33 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2006 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice-E is licensed to you under the terms described in the
+// ICEE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+import Test.*;
+
+public final class RetryI extends _RetryDisp
+{
+ public
+ RetryI()
+ {
+ }
+
+ public void
+ op(boolean kill, Ice.Current current)
+ {
+ if(kill)
+ {
+ current.con.close(true);
+ }
+ }
+
+ public void
+ shutdown(Ice.Current current)
+ {
+ current.adapter.getCommunicator().shutdown();
+ }
+}
diff --git a/java/test/Ice/retry/Server.java b/java/test/Ice/retry/Server.java
new file mode 100644
index 00000000000..e8404acabf8
--- /dev/null
+++ b/java/test/Ice/retry/Server.java
@@ -0,0 +1,66 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice-E is licensed to you under the terms described in the
+// ICEE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+public class Server
+{
+ public static int
+ run(String[] args, Ice.Communicator communicator, java.io.PrintStream out)
+ {
+ //
+ // When running as a MIDlet the properties for the server may be
+ // overridden by configuration. If it isn't then we assume
+ // defaults.
+ //
+ if(communicator.getProperties().getProperty("TestAdapter.Endpoints").length() == 0)
+ {
+ communicator.getProperties().setProperty("TestAdapter.Endpoints", "default -p 12010 -t 10000");
+ }
+
+ Ice.ObjectAdapter adapter = communicator.createObjectAdapter("TestAdapter");
+ adapter.add(new RetryI(), Ice.Util.stringToIdentity("retry"));
+ adapter.activate();
+
+ communicator.waitForShutdown();
+ return 0;
+ }
+
+ public static void
+ main(String[] args)
+ {
+ int status = 0;
+ Ice.Communicator communicator = null;
+
+ try
+ {
+ communicator = Ice.Util.initialize(args);
+ status = run(args, communicator, System.out);
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ status = 1;
+ }
+
+ if(communicator != null)
+ {
+ try
+ {
+ communicator.destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ status = 1;
+ }
+ }
+
+ System.gc();
+ System.exit(status);
+ }
+}
diff --git a/java/src/IceInternal/NonRepeatable.java b/java/test/Ice/retry/Test.ice
index c82a8077ebb..688b0fcb5da 100644
--- a/java/src/IceInternal/NonRepeatable.java
+++ b/java/test/Ice/retry/Test.ice
@@ -7,21 +7,18 @@
//
// **********************************************************************
-package IceInternal;
+#ifndef TEST_ICE
+#define TEST_ICE
-public class NonRepeatable extends Exception
+module Test
{
- public
- NonRepeatable(Ice.LocalException ex)
- {
- _ex = ex;
- }
- public Ice.LocalException
- get()
- {
- return _ex;
- }
+interface Retry
+{
+ ["ami"] void op(bool kill);
+ void shutdown();
+};
+
+};
- private Ice.LocalException _ex;
-}
+#endif
diff --git a/java/test/Ice/retry/build.xml b/java/test/Ice/retry/build.xml
new file mode 100644
index 00000000000..37cf2231693
--- /dev/null
+++ b/java/test/Ice/retry/build.xml
@@ -0,0 +1,58 @@
+<!--
+ **********************************************************************
+
+ Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+
+ This copy of Ice is licensed to you under the terms described in the
+ ICE_LICENSE file included in this distribution.
+
+ **********************************************************************
+-->
+
+<!DOCTYPE project [
+<!ENTITY common SYSTEM "file:../../../config/common.xml">
+]>
+
+<project name="test_Ice_retry" default="all" basedir=".">
+
+ <!-- set global properties for this build -->
+ <property name="top.dir" value="../../.."/>
+
+ <!-- Include common definitions -->
+ &common;
+
+ <property name="class.dir" value="classes"/>
+ <property name="generated.dir" value="generated"/>
+
+ <target name="init" depends="config-init">
+ <!-- Create the time stamp -->
+ <tstamp/>
+ </target>
+
+ <target name="generate" depends="init">
+ <!-- Create the output directory for generated code -->
+ <mkdir dir="${generated.dir}"/>
+ <slice2java outputdir="${generated.dir}">
+ <fileset dir="." includes="Test.ice"/>
+ <includepath>
+ <pathelement path="${slice.dir}" />
+ </includepath>
+ </slice2java>
+ </target>
+
+ <target name="compile" depends="generate">
+ <mkdir dir="${class.dir}"/>
+ <javac srcdir="${generated.dir}" destdir="${class.dir}"
+ source="1.4" classpath="${lib.dir}" debug="${debug}"/>
+ <javac srcdir="." destdir="${class.dir}" source="1.4"
+ classpath="${lib.dir}" excludes="generated/**" debug="${debug}"/>
+ </target>
+
+ <target name="all" depends="compile"/>
+
+ <target name="clean">
+ <delete dir="${generated.dir}"/>
+ <delete dir="${class.dir}"/>
+ </target>
+
+</project>
diff --git a/java/test/Ice/retry/run.py b/java/test/Ice/retry/run.py
new file mode 100755
index 00000000000..3266f26b780
--- /dev/null
+++ b/java/test/Ice/retry/run.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice-E is licensed to you under the terms described in the
+# ICEE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys
+
+for toplevel in [".", "..", "../..", "../../..", "../../../.."]:
+ toplevel = os.path.normpath(toplevel)
+ if os.path.exists(os.path.join(toplevel, "config", "TestUtil.py")):
+ break
+else:
+ raise "can't find toplevel directory!"
+
+sys.path.append(os.path.join(toplevel, "config"))
+import TestUtil
+
+name = os.path.join("Ice", "retry")
+testdir = os.path.join(toplevel, "test", name)
+
+classpath = os.getenv("CLASSPATH", "")
+os.environ["CLASSPATH"] = os.path.join(testdir, "classes") + TestUtil.sep + classpath
+TestUtil.clientServerTest()
+sys.exit(0)
diff --git a/py/allTests.py b/py/allTests.py
index 17ecf59a03b..01f71dfe1d2 100755
--- a/py/allTests.py
+++ b/py/allTests.py
@@ -61,6 +61,7 @@ tests = [ \
"Ice/slicing/exceptions", \
"Ice/slicing/objects", \
"Ice/checksum", \
+ "Ice/retry", \
]
def usage():
diff --git a/py/test/Ice/retry/AllTests.py b/py/test/Ice/retry/AllTests.py
new file mode 100644
index 00000000000..504c186af67
--- /dev/null
+++ b/py/test/Ice/retry/AllTests.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import Ice, Test, threading
+
+def test(b):
+ if not b:
+ raise RuntimeError('test assertion failed')
+
+class CallbackBase:
+ def __init__(self):
+ self._called = False
+ self._cond = threading.Condition()
+
+ def check(self):
+ self._cond.acquire()
+ try:
+ while not self._called:
+ self._cond.wait(5.0)
+ if self._called:
+ self._called = False
+ return True
+ else:
+ return False
+ finally:
+ self._cond.release()
+
+ def called(self):
+ self._cond.acquire()
+ self._called = True
+ self._cond.notify()
+ self._cond.release()
+
+class AMIRegular(CallbackBase):
+ def __init__(self):
+ CallbackBase.__init__(self)
+
+ def ice_response(self):
+ self.called()
+
+ def ice_exception(self, ex):
+ test(False)
+
+class AMIException(CallbackBase):
+ def __init__(self):
+ CallbackBase.__init__(self)
+
+ def ice_response(self):
+ test(False)
+
+ def ice_exception(self, ex):
+ test(isinstance(ex, Ice.ConnectionLostException))
+ self.called()
+
+def allTests(communicator):
+ print "testing stringToProxy...",
+ ref = "retry:default -p 12010 -t 10000"
+ base1 = communicator.stringToProxy(ref)
+ test(base1)
+ base2 = communicator.stringToProxy(ref)
+ test(base2)
+ print "ok"
+
+ print "testing checked cast...",
+ retry1 = Test.RetryPrx.checkedCast(base1)
+ test(retry1)
+ test(retry1 == base1)
+ retry2 = Test.RetryPrx.checkedCast(base2)
+ test(retry2)
+ test(retry2 == base2)
+ print "ok"
+
+ print "calling regular operation with first proxy...",
+ retry1.op(False)
+ print "ok"
+
+ print "calling operation to kill connection with second proxy...",
+ try:
+ retry2.op(True)
+ test(False)
+ except Ice.ConnectionLostException:
+ print "ok"
+
+ print "calling regular operation with first proxy again...",
+ retry1.op(False)
+ print "ok"
+
+ cb1 = AMIRegular()
+ cb2 = AMIException()
+
+ print "calling regular AMI operation with first proxy...",
+ retry1.op_async(cb1, False)
+ test(cb1.check())
+ print "ok"
+
+ print "calling AMI operation to kill connection with second proxy...",
+ retry2.op_async(cb2, True)
+ test(cb2.check())
+ print "ok"
+
+ print "calling regular AMI operation with first proxy again...",
+ retry1.op_async(cb1, False)
+ test(cb1.check())
+ print "ok"
+
+ return retry1
+ return retry1
diff --git a/py/test/Ice/retry/Client.py b/py/test/Ice/retry/Client.py
new file mode 100644
index 00000000000..614676fb090
--- /dev/null
+++ b/py/test/Ice/retry/Client.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys, traceback
+
+for toplevel in [".", "..", "../..", "../../..", "../../../.."]:
+ toplevel = os.path.normpath(toplevel)
+ if os.path.exists(os.path.join(toplevel, "python", "Ice.py")):
+ break
+else:
+ raise "can't find toplevel directory!"
+
+sys.path.insert(0, os.path.join(toplevel, "python"))
+sys.path.insert(0, os.path.join(toplevel, "lib"))
+
+#
+# Find Slice directory.
+#
+slice_dir = os.getenv('ICEPY_HOME', '')
+if len(slice_dir) == 0 or not os.path.exists(os.path.join(slice_dir, "slice")):
+ slice_dir = os.getenv('ICE_HOME', '')
+if len(slice_dir) == 0 or not os.path.exists(os.path.join(slice_dir, "slice")):
+ print sys.argv[0] + ': Slice directory not found. Define ICEPY_HOME or ICE_HOME.'
+ sys.exit(1)
+
+import Ice
+Ice.loadSlice('-I' + slice_dir + '/slice Test.ice')
+import AllTests
+
+def test(b):
+ if not b:
+ raise RuntimeError('test assertion failed')
+
+def run(args, communicator):
+ retry = AllTests.allTests(communicator)
+ retry.shutdown()
+ return True
+
+try:
+ #
+ # In this test, we need at least two threads in the
+ # client side thread pool for nested AMI.
+ #
+ properties = Ice.getDefaultProperties(sys.argv)
+ properties.setProperty('Ice.RetryIntervals', '-1')
+
+ communicator = Ice.initialize(sys.argv)
+ properties.setProperty('Ice.Warn.Connections', '0')
+ status = run(sys.argv, communicator)
+except:
+ traceback.print_exc()
+ status = False
+
+if communicator:
+ try:
+ communicator.destroy()
+ except:
+ traceback.print_exc()
+ status = False
+
+sys.exit(not status)
diff --git a/py/test/Ice/retry/Server.py b/py/test/Ice/retry/Server.py
new file mode 100644
index 00000000000..887e7e9cef6
--- /dev/null
+++ b/py/test/Ice/retry/Server.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys, traceback
+
+for toplevel in [".", "..", "../..", "../../..", "../../../.."]:
+ toplevel = os.path.normpath(toplevel)
+ if os.path.exists(os.path.join(toplevel, "python", "Ice.py")):
+ break
+else:
+ raise "can't find toplevel directory!"
+
+sys.path.insert(0, os.path.join(toplevel, "python"))
+sys.path.insert(0, os.path.join(toplevel, "lib"))
+
+import Ice
+
+#
+# Find Slice directory.
+#
+slice_dir = os.getenv('ICEPY_HOME', '')
+if len(slice_dir) == 0 or not os.path.exists(os.path.join(slice_dir, "slice")):
+ slice_dir = os.getenv('ICE_HOME', '')
+if len(slice_dir) == 0 or not os.path.exists(os.path.join(slice_dir, "slice")):
+ print sys.argv[0] + ': Slice directory not found. Define ICEPY_HOME or ICE_HOME.'
+ sys.exit(1)
+
+Ice.loadSlice('-I' + slice_dir + '/slice Test.ice')
+import Test, TestI
+
+def run(args, communicator):
+ communicator.getProperties().setProperty("TestAdapter.Endpoints", "default -p 12010 -t 10000:udp")
+ adapter = communicator.createObjectAdapter("TestAdapter")
+ id = Ice.stringToIdentity("retry")
+ adapter.add(TestI.RetryI(), id)
+ adapter.activate()
+ communicator.waitForShutdown()
+ return True
+
+try:
+ communicator = Ice.initialize(sys.argv)
+ status = run(sys.argv, communicator)
+except:
+ traceback.print_exc()
+ status = False
+
+if communicator:
+ try:
+ communicator.destroy()
+ except:
+ traceback.print_exc()
+ status = False
+
+sys.exit(not status)
diff --git a/py/test/Ice/retry/Test.ice b/py/test/Ice/retry/Test.ice
new file mode 100644
index 00000000000..688b0fcb5da
--- /dev/null
+++ b/py/test/Ice/retry/Test.ice
@@ -0,0 +1,24 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#ifndef TEST_ICE
+#define TEST_ICE
+
+module Test
+{
+
+interface Retry
+{
+ ["ami"] void op(bool kill);
+ void shutdown();
+};
+
+};
+
+#endif
diff --git a/py/test/Ice/retry/TestI.py b/py/test/Ice/retry/TestI.py
new file mode 100644
index 00000000000..9101583ef83
--- /dev/null
+++ b/py/test/Ice/retry/TestI.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import Ice, Test
+
+class RetryI(Test.Retry):
+
+ def op(self, kill, current=None):
+ if kill:
+ current.con.close(True)
+
+ def shutdown(self, current=None):
+ current.adapter.getCommunicator().shutdown()
diff --git a/py/test/Ice/retry/run.py b/py/test/Ice/retry/run.py
new file mode 100755
index 00000000000..9c43edcfe72
--- /dev/null
+++ b/py/test/Ice/retry/run.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+#
+# This copy of Ice is licensed to you under the terms described in the
+# ICE_LICENSE file included in this distribution.
+#
+# **********************************************************************
+
+import os, sys
+
+for toplevel in [".", "..", "../..", "../../..", "../../../.."]:
+ toplevel = os.path.normpath(toplevel)
+ if os.path.exists(os.path.join(toplevel, "config", "TestUtil.py")):
+ break
+else:
+ raise "can't find toplevel directory!"
+
+sys.path.append(os.path.join(toplevel, "config"))
+import TestUtil
+
+name = os.path.join("Ice", "retry")
+
+TestUtil.clientServerTest(name)
+sys.exit(0)