diff options
author | Jose <jose@zeroc.com> | 2008-12-18 14:32:27 +0100 |
---|---|---|
committer | Jose <jose@zeroc.com> | 2008-12-18 14:32:27 +0100 |
commit | 57a0a4333fbb0b41cd7423b37b59534455a3173b (patch) | |
tree | 174b28cf580405b213ae4da8fd96b2ca509bd9aa /java/src | |
parent | Merge branch 'R3_3_branch'; commit 'origin/R3_3_branch' into R3_3_branch (diff) | |
download | ice-57a0a4333fbb0b41cd7423b37b59534455a3173b.tar.bz2 ice-57a0a4333fbb0b41cd7423b37b59534455a3173b.tar.xz ice-57a0a4333fbb0b41cd7423b37b59534455a3173b.zip |
Revert "Remove Java finalizers code"
This reverts commit 94e1da6dc82a8ed38ee7a5691d691d375aaa28cb.
Diffstat (limited to 'java/src')
26 files changed, 392 insertions, 21 deletions
diff --git a/java/src/Freeze/ConnectionI.java b/java/src/Freeze/ConnectionI.java index 3913ec614a6..45053c39556 100644 --- a/java/src/Freeze/ConnectionI.java +++ b/java/src/Freeze/ConnectionI.java @@ -61,6 +61,12 @@ class ConnectionI implements Connection } + public void + close() + { + close(false); + } + public Ice.Communicator getCommunicator() { @@ -73,11 +79,23 @@ class ConnectionI implements Connection return _envName; } - public void - close() + protected void + finalize() + { + close(true); + } + + void + close(boolean finalizing) { if(_transaction != null) { + if(finalizing) + { + _communicator.getLogger().warning + ("Finalizing Connection on DbEnv \"" + _envName + "\" with active transaction"); + } + try { _transaction.rollback(); @@ -96,7 +114,7 @@ class ConnectionI implements Connection java.util.Iterator p = _mapList.iterator(); while(p.hasNext()) { - ((Map) p.next()).close(); + ((Map) p.next()).close(finalizing); } } @@ -124,6 +142,7 @@ class ConnectionI implements Connection Ice.Properties properties = _communicator.getProperties(); _deadlockWarning = properties.getPropertyAsInt("Freeze.Warn.Deadlocks") > 0; + _closeInFinalizeWarning = properties.getPropertyAsIntWithDefault("Freeze.Warn.CloseInFinalize", 1) > 0; } ConnectionI(Ice.Communicator communicator, String envName, com.sleepycat.db.Environment dbEnv) @@ -216,6 +235,11 @@ class ConnectionI implements Connection return _deadlockWarning; } + final boolean + closeInFinalizeWarning() + { + return _closeInFinalizeWarning; + } private String errorPrefix() { @@ -231,4 +255,5 @@ class ConnectionI implements Connection private int _trace; private int _txTrace; private boolean _deadlockWarning; + private boolean _closeInFinalizeWarning; } diff --git a/java/src/Freeze/EvictorI.java b/java/src/Freeze/EvictorI.java index 576760e7062..51b62e314dc 100644 --- a/java/src/Freeze/EvictorI.java +++ b/java/src/Freeze/EvictorI.java @@ -273,6 +273,17 @@ abstract class EvictorI implements Evictor abstract protected void evict(); + + synchronized protected void + finalize() + { + if(!_deactivateController.deactivated()) + { + _communicator.getLogger().warning("Freeze evictor " + toString() + " has not been deactivated"); + deactivate(""); + } + } + protected void closeDbEnv() { diff --git a/java/src/Freeze/Map.java b/java/src/Freeze/Map.java index 6b9ce2ab8b7..b2ad20012c0 100644 --- a/java/src/Freeze/Map.java +++ b/java/src/Freeze/Map.java @@ -281,9 +281,15 @@ public abstract class Map extends java.util.AbstractMap } public void + close() + { + close(false); + } + + public void closeDb() { - close(); + close(false); _connection.dbEnv().removeSharedMapDb(_dbName); } @@ -837,7 +843,7 @@ public abstract class Map extends java.util.AbstractMap public void closeAllIterators() { - closeAllIteratorsExcept(null); + closeAllIteratorsExcept(null, false); } @@ -957,7 +963,7 @@ public abstract class Map extends java.util.AbstractMap void - closeAllIteratorsExcept(Object except) + closeAllIteratorsExcept(Object except, boolean finalizing) { synchronized(_iteratorList) { @@ -968,29 +974,38 @@ public abstract class Map extends java.util.AbstractMap Object obj = p.next(); if(obj != except) { - ((EntryIteratorImpl)obj).close(); + ((EntryIteratorImpl)obj).close(finalizing); } } } } + protected void + finalize() + { + close(true); + } + // // The synchronization is only needed when finalizing is true // - public void - close() + void + close(boolean finalizing) { - if(_db != null) + synchronized(_connection) { - try - { - closeAllIteratorsExcept(null); - } - finally + if(_db != null) { - _db = null; - _connection.unregisterMap(_token); - _token = null; + try + { + closeAllIteratorsExcept(null, finalizing); + } + finally + { + _db = null; + _connection.unregisterMap(_token); + _token = null; + } } } } @@ -1920,7 +1935,7 @@ public abstract class Map extends java.util.AbstractMap { if(_txn != null) { - closeAllIteratorsExcept(this); + closeAllIteratorsExcept(this, false); } // @@ -2019,9 +2034,30 @@ public abstract class Map extends java.util.AbstractMap } } + // + // Extra operations. + // public void close() { + close(false); + } + + // + // The synchronized is needed because this method can be called + // concurrently by Connection, Map and Map.EntryIterator finalizers. + // + synchronized void + close(boolean finalizing) + { + if(finalizing && (_cursor != null || _txn != null) && _connection.closeInFinalizeWarning()) + { + _connection.communicator().getLogger().warning( + "finalize() closing a live iterator on Map \"" + _db.dbName() + "\"; the application " + + "should have closed it earlier by calling Map.EntryIterator.close(), " + + "Map.closeAllIterators(), Map.close(), Connection.close(), or (if also " + + "leaking a transaction) Transaction.commit() or Transaction.rollback()"); + } if(_iteratorListToken != null) { @@ -2102,6 +2138,12 @@ public abstract class Map extends java.util.AbstractMap close(); } + protected void + finalize() + { + close(true); + } + void setValue(Map.Entry entry, Object value) { @@ -2113,7 +2155,7 @@ public abstract class Map extends java.util.AbstractMap if(_txn != null) { - closeAllIteratorsExcept(this); + closeAllIteratorsExcept(this, false); } // diff --git a/java/src/Freeze/TransactionalEvictorContext.java b/java/src/Freeze/TransactionalEvictorContext.java index 50fe354ef7c..2de368abeb0 100644 --- a/java/src/Freeze/TransactionalEvictorContext.java +++ b/java/src/Freeze/TransactionalEvictorContext.java @@ -351,6 +351,17 @@ class TransactionalEvictorContext implements Ice.DispatchInterceptorAsyncCallbac } return null; } + + + protected void + finalize() + { + if(_tx != null) + { + _tx.getConnectionI().communicator().getLogger().warning + ("Finalizing incomplete TransactionalEvictorContext on DbEnv '" + _tx.getConnectionI().dbEnv().getEnvName() + "'"); + } + } private ServantHolder findServantHolder(Ice.Identity ident, ObjectStore store) diff --git a/java/src/Ice/CommunicatorI.java b/java/src/Ice/CommunicatorI.java index 73a77567aa6..8562f0fd7ac 100644 --- a/java/src/Ice/CommunicatorI.java +++ b/java/src/Ice/CommunicatorI.java @@ -196,6 +196,23 @@ public final class CommunicatorI implements Communicator _instance = new IceInternal.Instance(this, initData); } + /** + * For compatibility with C#, we do not invoke methods on other objects + * from within a finalizer. + * + protected synchronized void + finalize() + throws Throwable + { + if(!_instance.destroyed()) + { + _instance.logger().warning("Ice::Communicator::destroy() has not been called"); + } + + super.finalize(); + } + */ + // // Certain initialization tasks need to be completed after the // constructor. diff --git a/java/src/Ice/ConnectionI.java b/java/src/Ice/ConnectionI.java index 170a1030658..eb9b2a88a76 100644 --- a/java/src/Ice/ConnectionI.java +++ b/java/src/Ice/ConnectionI.java @@ -1285,6 +1285,21 @@ public final class ConnectionI extends IceInternal.EventHandler implements Conne } } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_startCallback == null); + IceUtilInternal.Assert.FinalizerAssert(_state == StateClosed); + IceUtilInternal.Assert.FinalizerAssert(_transceiver == null); + IceUtilInternal.Assert.FinalizerAssert(_dispatchCount == 0); + IceUtilInternal.Assert.FinalizerAssert(_sendStreams.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_requests.isEmpty()); + IceUtilInternal.Assert.FinalizerAssert(_asyncRequests.isEmpty()); + + super.finalize(); + } + private static final int StateNotInitialized = 0; private static final int StateNotValidated = 1; private static final int StateActive = 2; diff --git a/java/src/Ice/ObjectAdapterI.java b/java/src/Ice/ObjectAdapterI.java index 61af2b359d6..5c6d7755cf1 100644 --- a/java/src/Ice/ObjectAdapterI.java +++ b/java/src/Ice/ObjectAdapterI.java @@ -355,6 +355,9 @@ public final class ObjectAdapterI implements ObjectAdapter // We're done, now we can throw away all incoming connection // factories. // + // For compatibility with C#, we set _incomingConnectionFactories + // to null so that the finalizer does not invoke methods on objects. + // _incomingConnectionFactories = null; // @@ -937,6 +940,32 @@ public final class ObjectAdapterI implements ObjectAdapter } } + protected synchronized void + finalize() + throws Throwable + { + if(!_deactivated) + { + _instance.initializationData().logger.warning("object adapter `" + getName() + + "' has not been deactivated"); + } + else if(!_destroyed) + { + _instance.initializationData().logger.warning("object adapter `" + getName() + "' has not been destroyed"); + } + else + { + IceUtilInternal.Assert.FinalizerAssert(_threadPool == null); + //IceUtilInternal.Assert.FinalizerAssert(_servantManager == null); // Not cleared, it needs to be immutable. + IceUtilInternal.Assert.FinalizerAssert(_communicator == null); + IceUtilInternal.Assert.FinalizerAssert(_incomingConnectionFactories == null); + IceUtilInternal.Assert.FinalizerAssert(_directCount == 0); + IceUtilInternal.Assert.FinalizerAssert(!_waitForActivate); + } + + super.finalize(); + } + private ObjectPrx newProxy(Identity ident, String facet) { diff --git a/java/src/IceInternal/ConnectionMonitor.java b/java/src/IceInternal/ConnectionMonitor.java index de7652e0069..6483c5242af 100644 --- a/java/src/IceInternal/ConnectionMonitor.java +++ b/java/src/IceInternal/ConnectionMonitor.java @@ -48,6 +48,16 @@ public final class ConnectionMonitor implements IceInternal.TimerTask _instance.timer().scheduleRepeated(this, interval * 1000); } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_instance == null); + IceUtilInternal.Assert.FinalizerAssert(_connections == null); + + super.finalize(); + } + public void runTimerTask() { diff --git a/java/src/IceInternal/IncomingConnectionFactory.java b/java/src/IceInternal/IncomingConnectionFactory.java index eae8c27151b..2a6b1263e2a 100644 --- a/java/src/IceInternal/IncomingConnectionFactory.java +++ b/java/src/IceInternal/IncomingConnectionFactory.java @@ -491,6 +491,17 @@ public final class IncomingConnectionFactory extends EventHandler implements Ice } } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_state == StateClosed); + IceUtilInternal.Assert.FinalizerAssert(_acceptor == null); + IceUtilInternal.Assert.FinalizerAssert(_connections == null); + + super.finalize(); + } + private static final int StateActive = 0; private static final int StateHolding = 1; private static final int StateClosed = 2; diff --git a/java/src/IceInternal/Instance.java b/java/src/IceInternal/Instance.java index 2cfd7ee8850..b4606bd206f 100644 --- a/java/src/IceInternal/Instance.java +++ b/java/src/IceInternal/Instance.java @@ -746,6 +746,31 @@ public final class Instance } } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_state == StateDestroyed); + IceUtilInternal.Assert.FinalizerAssert(_referenceFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_proxyFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_outgoingConnectionFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_connectionMonitor == null); + IceUtilInternal.Assert.FinalizerAssert(_servantFactoryManager == null); + IceUtilInternal.Assert.FinalizerAssert(_objectAdapterFactory == null); + IceUtilInternal.Assert.FinalizerAssert(_clientThreadPool == null); + IceUtilInternal.Assert.FinalizerAssert(_serverThreadPool == null); + IceUtilInternal.Assert.FinalizerAssert(_selectorThread == null); + IceUtilInternal.Assert.FinalizerAssert(_endpointHostResolver == null); + IceUtilInternal.Assert.FinalizerAssert(_timer == null); + IceUtilInternal.Assert.FinalizerAssert(_routerManager == null); + IceUtilInternal.Assert.FinalizerAssert(_locatorManager == null); + IceUtilInternal.Assert.FinalizerAssert(_endpointFactoryManager == null); + IceUtilInternal.Assert.FinalizerAssert(_pluginManager == null); + IceUtilInternal.Assert.FinalizerAssert(_retryQueue == null); + + super.finalize(); + } + public void finishSetup(Ice.StringSeqHolder args) { diff --git a/java/src/IceInternal/ObjectAdapterFactory.java b/java/src/IceInternal/ObjectAdapterFactory.java index e6a1790324a..9dd4779930f 100644 --- a/java/src/IceInternal/ObjectAdapterFactory.java +++ b/java/src/IceInternal/ObjectAdapterFactory.java @@ -262,6 +262,18 @@ public final class ObjectAdapterFactory _waitForShutdown = false; } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_instance == null); + IceUtilInternal.Assert.FinalizerAssert(_communicator == null); + IceUtilInternal.Assert.FinalizerAssert(_adapters == null); + IceUtilInternal.Assert.FinalizerAssert(!_waitForShutdown); + + super.finalize(); + } + private Instance _instance; private Ice.Communicator _communicator; private java.util.Map<String, Ice.ObjectAdapterI> _adapters = new java.util.HashMap<String, Ice.ObjectAdapterI>(); diff --git a/java/src/IceInternal/OutgoingAsyncMessageCallback.java b/java/src/IceInternal/OutgoingAsyncMessageCallback.java index 6e8cb9d807c..a0d21e7ad90 100644 --- a/java/src/IceInternal/OutgoingAsyncMessageCallback.java +++ b/java/src/IceInternal/OutgoingAsyncMessageCallback.java @@ -51,6 +51,14 @@ abstract public class OutgoingAsyncMessageCallback } } + protected synchronized void + finalize() + throws Throwable + { + assert(__os == null); + assert(__is == null); + } + protected void __acquireCallback(Ice.ObjectPrx proxy) { @@ -74,7 +82,7 @@ abstract public class OutgoingAsyncMessageCallback assert(__is == null); __is = new BasicStream(ref.getInstance()); assert(__os == null); - __os = new BasicStream(ref.getInstance()); + __os = new BasicStream(ref.getInstance()); } } diff --git a/java/src/IceInternal/OutgoingConnectionFactory.java b/java/src/IceInternal/OutgoingConnectionFactory.java index e6d8e6cad02..58177812f6d 100644 --- a/java/src/IceInternal/OutgoingConnectionFactory.java +++ b/java/src/IceInternal/OutgoingConnectionFactory.java @@ -417,6 +417,19 @@ public final class OutgoingConnectionFactory _destroyed = false; } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_destroyed); + IceUtilInternal.Assert.FinalizerAssert(_connections == null); + IceUtilInternal.Assert.FinalizerAssert(_connectionsByEndpoint == null); + IceUtilInternal.Assert.FinalizerAssert(_pendingConnectCount == 0); + IceUtilInternal.Assert.FinalizerAssert(_pending.isEmpty()); + + super.finalize(); + } + private java.util.List<EndpointI> applyOverrides(EndpointI[] endpts) { diff --git a/java/src/IceInternal/PropertyNames.java b/java/src/IceInternal/PropertyNames.java index 6dc0ec9fdd0..439d3a099cc 100644 --- a/java/src/IceInternal/PropertyNames.java +++ b/java/src/IceInternal/PropertyNames.java @@ -550,6 +550,7 @@ public final class PropertyNames new Property("Freeze\\.Trace\\.Evictor", false, null), new Property("Freeze\\.Trace\\.Map", false, null), new Property("Freeze\\.Trace\\.Transaction", false, null), + new Property("Freeze\\.Warn\\.CloseInFinalize", false, null), new Property("Freeze\\.Warn\\.Deadlocks", false, null), new Property("Freeze\\.Warn\\.Rollback", false, null), null diff --git a/java/src/IceInternal/SelectorThread.java b/java/src/IceInternal/SelectorThread.java index 6103a9e45a6..e34cc480ddc 100644 --- a/java/src/IceInternal/SelectorThread.java +++ b/java/src/IceInternal/SelectorThread.java @@ -40,6 +40,13 @@ public class SelectorThread _timer = _instance.timer(); } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_destroyed); + } + public synchronized void destroy() { diff --git a/java/src/IceInternal/ServantManager.java b/java/src/IceInternal/ServantManager.java index 931b383b7fe..8e4dcc1374a 100644 --- a/java/src/IceInternal/ServantManager.java +++ b/java/src/IceInternal/ServantManager.java @@ -199,6 +199,20 @@ public final class ServantManager _adapterName = adapterName; } + protected void + finalize() + throws Throwable + { + // + // Don't check whether destroy() has been called. It might have + // not been called if the associated object adapter was not + // properly deactivated. + // + //IceUtilInternal.Assert.FinalizerAssert(_instance == null); + + super.finalize(); + } + // // Only for use by Ice.ObjectAdapterI. // diff --git a/java/src/IceInternal/TcpAcceptor.java b/java/src/IceInternal/TcpAcceptor.java index bdbf6188ab2..e09bf7c760d 100644 --- a/java/src/IceInternal/TcpAcceptor.java +++ b/java/src/IceInternal/TcpAcceptor.java @@ -115,6 +115,15 @@ class TcpAcceptor implements Acceptor } } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + + super.finalize(); + } + private Instance _instance; private TraceLevels _traceLevels; private Ice.Logger _logger; diff --git a/java/src/IceInternal/TcpConnector.java b/java/src/IceInternal/TcpConnector.java index 3c7a76f960c..99a80dff1db 100644 --- a/java/src/IceInternal/TcpConnector.java +++ b/java/src/IceInternal/TcpConnector.java @@ -143,6 +143,13 @@ final class TcpConnector implements Connector, java.lang.Comparable } return Network.compareAddress(_addr, p._addr); + } + + protected synchronized void + finalize() + throws Throwable + { + super.finalize(); } private Instance _instance; diff --git a/java/src/IceInternal/TcpTransceiver.java b/java/src/IceInternal/TcpTransceiver.java index ac7715b9b15..548f2c3a94b 100644 --- a/java/src/IceInternal/TcpTransceiver.java +++ b/java/src/IceInternal/TcpTransceiver.java @@ -263,6 +263,15 @@ final class TcpTransceiver implements Transceiver } } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + + super.finalize(); + } + private java.nio.channels.SocketChannel _fd; private TraceLevels _traceLevels; private Ice.Logger _logger; diff --git a/java/src/IceInternal/ThreadPool.java b/java/src/IceInternal/ThreadPool.java index 3898fe0a0b6..6f19615ecf0 100644 --- a/java/src/IceInternal/ThreadPool.java +++ b/java/src/IceInternal/ThreadPool.java @@ -107,6 +107,13 @@ public final class ThreadPool } } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_destroyed); + } + public synchronized void destroy() { diff --git a/java/src/IceInternal/Timer.java b/java/src/IceInternal/Timer.java index 92d3f4c2300..b4805e22b6b 100644 --- a/java/src/IceInternal/Timer.java +++ b/java/src/IceInternal/Timer.java @@ -128,6 +128,15 @@ public final class Timer extends Thread start(); } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_instance == null); + + super.finalize(); + } + public void run() { diff --git a/java/src/IceInternal/UdpTransceiver.java b/java/src/IceInternal/UdpTransceiver.java index 85774a23607..84aef93ffb8 100644 --- a/java/src/IceInternal/UdpTransceiver.java +++ b/java/src/IceInternal/UdpTransceiver.java @@ -517,6 +517,15 @@ final class UdpTransceiver implements Transceiver { } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + + super.finalize(); + } + private TraceLevels _traceLevels; private Ice.Logger _logger; private Ice.Stats _stats; diff --git a/java/src/IceSSL/AcceptorI.java b/java/src/IceSSL/AcceptorI.java index 2e409429a31..29984ec9d6f 100644 --- a/java/src/IceSSL/AcceptorI.java +++ b/java/src/IceSSL/AcceptorI.java @@ -137,6 +137,15 @@ final class AcceptorI implements IceInternal.Acceptor } } + protected synchronized void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + + super.finalize(); + } + private Instance _instance; private String _adapterName; private Ice.Logger _logger; diff --git a/java/src/IceSSL/ConnectorI.java b/java/src/IceSSL/ConnectorI.java index e96a781f33a..370237563e8 100644 --- a/java/src/IceSSL/ConnectorI.java +++ b/java/src/IceSSL/ConnectorI.java @@ -156,6 +156,13 @@ final class ConnectorI implements IceInternal.Connector, java.lang.Comparable return IceInternal.Network.compareAddress(_addr, p._addr); } + protected synchronized void + finalize() + throws Throwable + { + super.finalize(); + } + private Instance _instance; private Ice.Logger _logger; private String _host; diff --git a/java/src/IceSSL/TransceiverI.java b/java/src/IceSSL/TransceiverI.java index eb95bff146a..3ef8a5c63d7 100644 --- a/java/src/IceSSL/TransceiverI.java +++ b/java/src/IceSSL/TransceiverI.java @@ -336,6 +336,15 @@ final class TransceiverI implements IceInternal.Transceiver _netOutput = ByteBuffer.allocateDirect(engine.getSession().getPacketBufferSize() * 2); } + protected void + finalize() + throws Throwable + { + IceUtilInternal.Assert.FinalizerAssert(_fd == null); + + super.finalize(); + } + private IceInternal.SocketStatus handshakeNonBlocking() { diff --git a/java/src/IceUtilInternal/Assert.java b/java/src/IceUtilInternal/Assert.java new file mode 100644 index 00000000000..314f20d8200 --- /dev/null +++ b/java/src/IceUtilInternal/Assert.java @@ -0,0 +1,45 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2008 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 IceUtilInternal; + +public final class Assert +{ + // + // The JVM ignores exceptions raised in finalizers, therefore finalizers + // that use assertions should call this method instead of assert(). + // + public static void + FinalizerAssert(boolean b) + { + if(!b) + { + // + // Create a Throwable to obtain the stack trace. + // + Throwable t = new Throwable(); + StackTraceElement[] trace = t.getStackTrace(); + if(trace.length > 1) + { + // + // Skip the first frame, which represents this method. + // + System.err.println("Assertion failure:"); + for(int i = 1; i < trace.length; ++i) + { + System.err.println("\tat " + trace[i]); + } + } + else + { + System.err.println("Assertion failure (no stack trace information)"); + } + } + } +} |