summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Newhook <matthew@zeroc.com>2006-12-22 18:52:53 +0000
committerMatthew Newhook <matthew@zeroc.com>2006-12-22 18:52:53 +0000
commit84d9f5c369fceccfa16401ed50783ed2ad209559 (patch)
tree689d30c8707629f1db8155edadb47ce1bce363ad
parentAdded autoflushing of batches (diff)
downloadice-84d9f5c369fceccfa16401ed50783ed2ad209559.tar.bz2
ice-84d9f5c369fceccfa16401ed50783ed2ad209559.tar.xz
ice-84d9f5c369fceccfa16401ed50783ed2ad209559.zip
http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=1391.
-rw-r--r--cpp/demo/Freeze/bench/Client.cpp13
-rw-r--r--cpp/demo/Freeze/library/Client.cpp25
-rw-r--r--cpp/demo/Freeze/library/Collocated.cpp25
-rw-r--r--cpp/demo/Freeze/phonebook/Client.cpp26
-rw-r--r--cpp/demo/Freeze/phonebook/Collocated.cpp25
-rw-r--r--cpp/demo/Glacier2/callback/Client.cpp25
-rwxr-xr-xcpp/demo/Glacier2/chat/Client.cpp97
-rw-r--r--cpp/demo/Ice/callback/Client.cpp25
-rw-r--r--cpp/demo/Ice/converter/Client.cpp5
-rw-r--r--cpp/demo/Ice/hello/Client.cpp25
-rw-r--r--cpp/demo/Ice/invoke/Client.cpp25
-rw-r--r--cpp/demo/Ice/nested/Client.cpp32
-rwxr-xr-xcpp/demo/Ice/session/Client.cpp96
-rw-r--r--cpp/demo/Ice/throughput/Client.cpp25
-rw-r--r--cpp/demo/Ice/value/Client.cpp25
-rw-r--r--cpp/demo/IceBox/hello/Client.cpp25
-rw-r--r--cpp/demo/IceGrid/allocate/Client.cpp121
-rw-r--r--cpp/demo/IceGrid/sessionActivation/Client.cpp113
-rw-r--r--cpp/demo/IceGrid/simple/Client.cpp24
-rw-r--r--cpp/include/Ice/Application.h12
-rw-r--r--cpp/src/Ice/Application.cpp110
-rw-r--r--java/demo/Freeze/library/Client.java23
-rw-r--r--java/demo/Freeze/library/Collocated.java23
-rw-r--r--java/demo/Freeze/phonebook/Client.java23
-rw-r--r--java/demo/Freeze/phonebook/Collocated.java23
-rw-r--r--java/demo/Glacier2/callback/Client.java23
-rw-r--r--java/demo/Ice/callback/Client.java23
-rw-r--r--java/demo/Ice/hello/Client.java24
-rw-r--r--java/demo/Ice/invoke/Client.java23
-rw-r--r--java/demo/Ice/nested/Client.java32
-rw-r--r--java/demo/Ice/session/Client.java101
-rw-r--r--java/demo/Ice/throughput/Client.java23
-rw-r--r--java/demo/Ice/value/Client.java23
-rw-r--r--java/demo/IceBox/hello/Client.java23
-rw-r--r--java/demo/IceGrid/allocate/Client.java72
-rw-r--r--java/demo/IceGrid/sessionActivation/Client.java70
-rw-r--r--java/demo/IceGrid/simple/Client.java23
-rw-r--r--java/src/Ice/Application.java271
38 files changed, 1394 insertions, 328 deletions
diff --git a/cpp/demo/Freeze/bench/Client.cpp b/cpp/demo/Freeze/bench/Client.cpp
index e0e70dac728..e0aaab24e2a 100644
--- a/cpp/demo/Freeze/bench/Client.cpp
+++ b/cpp/demo/Freeze/bench/Client.cpp
@@ -144,6 +144,7 @@ public:
TestApp(const string&);
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
@@ -717,6 +718,12 @@ typedef IceUtil::Handle<MyFactory> MyFactoryPtr;
int
TestApp::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
_connection = Freeze::createConnection(communicator(), _envName);
cout << "IntIntMap" << endl;
@@ -810,6 +817,12 @@ TestApp::run(int argc, char* argv[])
return EXIT_SUCCESS;
}
+void
+TestApp::interruptCallback(int)
+{
+ exit(EXIT_SUCCESS);
+}
+
int
main(int argc, char* argv[])
{
diff --git a/cpp/demo/Freeze/library/Client.cpp b/cpp/demo/Freeze/library/Client.cpp
index dab9aaa2607..f43eeedf738 100644
--- a/cpp/demo/Freeze/library/Client.cpp
+++ b/cpp/demo/Freeze/library/Client.cpp
@@ -15,6 +15,7 @@ using namespace std;
class LibraryClient : public Ice::Application
{
virtual int run(int argc, char* argv[]);
+ virtual void interruptCallback(int);
};
int
@@ -27,6 +28,30 @@ main(int argc, char* argv[])
int
LibraryClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
int runParser(int, char*[], const Ice::CommunicatorPtr&);
return runParser(argc, argv, communicator());
}
+
+void
+LibraryClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/Freeze/library/Collocated.cpp b/cpp/demo/Freeze/library/Collocated.cpp
index 4283dce2ef8..2d6fceb20e2 100644
--- a/cpp/demo/Freeze/library/Collocated.cpp
+++ b/cpp/demo/Freeze/library/Collocated.cpp
@@ -24,6 +24,7 @@ public:
}
virtual int run(int argc, char* argv[]);
+ virtual void interruptCallback(int);
private:
@@ -40,6 +41,12 @@ main(int argc, char* argv[])
int
LibraryCollocated::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
Ice::PropertiesPtr properties = communicator()->getProperties();
//
@@ -84,3 +91,21 @@ LibraryCollocated::run(int argc, char* argv[])
return status;
}
+
+void
+LibraryCollocated::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/Freeze/phonebook/Client.cpp b/cpp/demo/Freeze/phonebook/Client.cpp
index 625041380a5..2478d5f7429 100644
--- a/cpp/demo/Freeze/phonebook/Client.cpp
+++ b/cpp/demo/Freeze/phonebook/Client.cpp
@@ -11,9 +11,11 @@
using namespace std;
+
class PhoneBookClient : public Ice::Application
{
virtual int run(int argc, char* argv[]);
+ virtual void interruptCallback(int);
};
int
@@ -26,6 +28,30 @@ main(int argc, char* argv[])
int
PhoneBookClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
int runParser(int, char*[], const Ice::CommunicatorPtr&);
return runParser(argc, argv, communicator());
}
+
+void
+PhoneBookClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/Freeze/phonebook/Collocated.cpp b/cpp/demo/Freeze/phonebook/Collocated.cpp
index cb213a9da87..e979700f651 100644
--- a/cpp/demo/Freeze/phonebook/Collocated.cpp
+++ b/cpp/demo/Freeze/phonebook/Collocated.cpp
@@ -24,6 +24,7 @@ public:
}
virtual int run(int argc, char* argv[]);
+ virtual void interruptCallback(int);
private:
@@ -40,6 +41,12 @@ main(int argc, char* argv[])
int
PhoneBookCollocated::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
Ice::PropertiesPtr properties = communicator()->getProperties();
//
@@ -101,3 +108,21 @@ PhoneBookCollocated::run(int argc, char* argv[])
return status;
}
+
+void
+PhoneBookCollocated::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/Glacier2/callback/Client.cpp b/cpp/demo/Glacier2/callback/Client.cpp
index 42e32317fe1..54a391b24ef 100644
--- a/cpp/demo/Glacier2/callback/Client.cpp
+++ b/cpp/demo/Glacier2/callback/Client.cpp
@@ -19,6 +19,7 @@ class CallbackClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
};
int
@@ -47,6 +48,12 @@ menu()
int
CallbackClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter();
if(!defaultRouter)
{
@@ -208,3 +215,21 @@ CallbackClient::run(int argc, char* argv[])
return EXIT_SUCCESS;
}
+
+void
+CallbackClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/Glacier2/chat/Client.cpp b/cpp/demo/Glacier2/chat/Client.cpp
index 59cedc50e6b..5c4c8dccb05 100755
--- a/cpp/demo/Glacier2/chat/Client.cpp
+++ b/cpp/demo/Glacier2/chat/Client.cpp
@@ -93,16 +93,23 @@ public:
virtual int
run(int argc, char* argv[])
{
- Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter();
- if(!defaultRouter)
- {
- cerr << argv[0] << ": no default router set" << endl;
- return EXIT_FAILURE;
- }
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
- Glacier2::RouterPrx router = Glacier2::RouterPrx::checkedCast(defaultRouter);
{
- if(!router)
+ IceUtil::Mutex::Lock sync(_mutex);
+ Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter();
+ if(!defaultRouter)
+ {
+ cerr << argv[0] << ": no default router set" << endl;
+ return EXIT_FAILURE;
+ }
+
+ _router = Glacier2::RouterPrx::checkedCast(defaultRouter);
+ if(!_router)
{
cerr << argv[0] << ": configured router is not a Glacier2 router" << endl;
return EXIT_FAILURE;
@@ -126,7 +133,7 @@ public:
try
{
- session = ChatSessionPrx::uncheckedCast(router->createSession(id, pw));
+ session = ChatSessionPrx::uncheckedCast(_router->createSession(id, pw));
break;
}
catch(const Glacier2::PermissionDeniedException& ex)
@@ -135,12 +142,15 @@ public:
}
}
- SessionPingThreadPtr ping = new SessionPingThread(session, (long)router->getSessionTimeout() / 2);
- ping->start();
+ {
+ IceUtil::Mutex::Lock sync(_mutex);
+ _ping = new SessionPingThread(session, (long)_router->getSessionTimeout() / 2);
+ _ping->start();
+ }
Ice::Identity callbackReceiverIdent;
callbackReceiverIdent.name = "callbackReceiver";
- callbackReceiverIdent.category = router->getCategoryForClient();
+ callbackReceiverIdent.category = _router->getCategoryForClient();
Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Chat.Client");
ChatCallbackPrx callback = ChatCallbackPrx::uncheckedCast(
@@ -177,9 +187,47 @@ public:
}
while(cin.good());
+ cleanup();
+ }
+ catch(const Ice::Exception& ex)
+ {
+ cerr << ex << endl;
+ cleanup();
+
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
+
+ virtual void
+ interruptCallback(int)
+ {
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+ }
+
+private:
+
+ void
+ cleanup()
+ {
+ IceUtil::Mutex::Lock sync(_mutex);
+ if(_router)
+ {
try
{
- router->destroySession();
+ _router->destroySession();
}
catch(const Ice::ConnectionLostException&)
{
@@ -187,25 +235,16 @@ public:
// Expected: the router closed the connection.
//
}
+ _router = 0;
}
- catch(const Ice::Exception& ex)
+ if(_ping)
{
- cerr << ex << endl;
-
- ping->destroy();
- ping->getThreadControl().join();
-
- return EXIT_FAILURE;
+ _ping->destroy();
+ _ping->getThreadControl().join();
+ _ping = 0;
}
-
- ping->destroy();
- ping->getThreadControl().join();
-
- return EXIT_SUCCESS;
}
-private:
-
void
menu()
{
@@ -223,6 +262,10 @@ private:
}
return s;
}
+
+ IceUtil::Mutex _mutex;
+ Glacier2::RouterPrx _router;
+ SessionPingThreadPtr _ping;
};
int
diff --git a/cpp/demo/Ice/callback/Client.cpp b/cpp/demo/Ice/callback/Client.cpp
index 8a6b237b415..0f40c0371a1 100644
--- a/cpp/demo/Ice/callback/Client.cpp
+++ b/cpp/demo/Ice/callback/Client.cpp
@@ -28,6 +28,7 @@ class CallbackClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
@@ -44,6 +45,12 @@ main(int argc, char* argv[])
int
CallbackClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
CallbackSenderPrx twoway = CallbackSenderPrx::checkedCast(
communicator()->propertyToProxy("Callback.Client.CallbackServer")->
ice_twoway()->ice_timeout(-1)->ice_secure(false));
@@ -169,6 +176,24 @@ CallbackClient::run(int argc, char* argv[])
}
void
+CallbackClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
CallbackClient::menu()
{
cout <<
diff --git a/cpp/demo/Ice/converter/Client.cpp b/cpp/demo/Ice/converter/Client.cpp
index 8864838bf69..e833dbc3b48 100644
--- a/cpp/demo/Ice/converter/Client.cpp
+++ b/cpp/demo/Ice/converter/Client.cpp
@@ -113,7 +113,10 @@ main(int argc, char* argv[])
initData.properties->load("config.client");
communicator1 = Ice::initialize(argc, argv, initData);
- communicator2 = Ice::initialize(argc, argv);
+ Ice::InitializationData initData2;
+ initData2.properties = Ice::createProperties();
+ initData2.properties->load("config.client");
+ communicator2 = Ice::initialize(argc, argv, initData2);
status = run(argc, argv, communicator1, communicator2);
}
diff --git a/cpp/demo/Ice/hello/Client.cpp b/cpp/demo/Ice/hello/Client.cpp
index 3aca8c3d934..f2de173ada6 100644
--- a/cpp/demo/Ice/hello/Client.cpp
+++ b/cpp/demo/Ice/hello/Client.cpp
@@ -18,6 +18,7 @@ class HelloClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
@@ -34,6 +35,12 @@ main(int argc, char* argv[])
int
HelloClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
HelloPrx twoway = HelloPrx::checkedCast(
communicator()->propertyToProxy("Hello.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false));
if(!twoway)
@@ -189,6 +196,24 @@ HelloClient::run(int argc, char* argv[])
}
void
+HelloClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
HelloClient::menu()
{
cout <<
diff --git a/cpp/demo/Ice/invoke/Client.cpp b/cpp/demo/Ice/invoke/Client.cpp
index 3a687a5e29f..0bfe715f5d1 100644
--- a/cpp/demo/Ice/invoke/Client.cpp
+++ b/cpp/demo/Ice/invoke/Client.cpp
@@ -18,6 +18,7 @@ class InvokeClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
@@ -52,6 +53,12 @@ operator<<(ostream& out, Demo::Color c)
int
InvokeClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
Ice::ObjectPrx obj = communicator()->propertyToProxy("Printer.Proxy");
menu();
@@ -293,6 +300,24 @@ InvokeClient::run(int argc, char* argv[])
}
void
+InvokeClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
InvokeClient::menu()
{
cout <<
diff --git a/cpp/demo/Ice/nested/Client.cpp b/cpp/demo/Ice/nested/Client.cpp
index 53d9ae26547..bc10109a1fe 100644
--- a/cpp/demo/Ice/nested/Client.cpp
+++ b/cpp/demo/Ice/nested/Client.cpp
@@ -13,11 +13,13 @@
using namespace std;
using namespace Demo;
+
class NestedClient : public Ice::Application
{
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
};
int
@@ -30,6 +32,12 @@ main(int argc, char* argv[])
int
NestedClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
NestedPrx nested = NestedPrx::checkedCast(communicator()->propertyToProxy("Nested.Client.NestedServer"));
if(!nested)
{
@@ -70,3 +78,27 @@ NestedClient::run(int argc, char* argv[])
return EXIT_SUCCESS;
}
+
+void
+NestedClient::interruptCallback(int)
+{
+/*
+ * For this demo we won't destroy the communicator since it has to
+ * wait for any outstanding invocations to complete which may take
+ * some time if the nesting level is exceeded.
+ *
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+*/
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/Ice/session/Client.cpp b/cpp/demo/Ice/session/Client.cpp
index fc78b4dee0c..e0be25f7d61 100755
--- a/cpp/demo/Ice/session/Client.cpp
+++ b/cpp/demo/Ice/session/Client.cpp
@@ -72,10 +72,20 @@ class SessionClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
void menu();
+ void cleanup(bool);
+
+ //
+ // The interrupt callback and main can run concurrently with one
+ // another so shared variables must be mutex protected.
+ //
+ IceUtil::Mutex _mutex;
+ SessionRefreshThreadPtr _refresh;
+ SessionPrx _session;
};
int
@@ -88,6 +98,12 @@ main(int argc, char* argv[])
int
SessionClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
string name;
cout << "Please enter your name ==> ";
cin >> name;
@@ -104,11 +120,14 @@ SessionClient::run(int argc, char* argv[])
return EXIT_FAILURE;
}
- SessionPrx session = factory->create(name);
-
- SessionRefreshThreadPtr refresh = new SessionRefreshThread(
- communicator()->getLogger(), IceUtil::Time::seconds(5), session);
- refresh->start();
+ {
+ IceUtil::Mutex::Lock sync(_mutex);
+ _session = factory->create(name);
+
+ _refresh = new SessionRefreshThread(
+ communicator()->getLogger(), IceUtil::Time::seconds(5), _session);
+ _refresh->start();
+ }
vector<HelloPrx> hellos;
@@ -144,7 +163,7 @@ SessionClient::run(int argc, char* argv[])
}
else if(c == 'c')
{
- hellos.push_back(session->createHello());
+ hellos.push_back(_session->createHello());
cout << "Created hello object " << hellos.size() - 1 << endl;
}
else if(c == 's')
@@ -179,14 +198,7 @@ SessionClient::run(int argc, char* argv[])
// is set to 0 so that if session->destroy() raises an exception
// the thread will not be re-terminated and re-joined.
//
- refresh->terminate();
- refresh->getThreadControl().join();
- refresh = 0;
-
- if(destroy)
- {
- session->destroy();
- }
+ cleanup(destroy);
if(shutdown)
{
factory->shutdown();
@@ -194,14 +206,12 @@ SessionClient::run(int argc, char* argv[])
}
catch(...)
{
- //
- // The refresher thread must be terminated in the event of a
- // failure.
- //
- if(refresh)
+ try
+ {
+ cleanup(true);
+ }
+ catch(...)
{
- refresh->terminate();
- refresh->getThreadControl().join();
}
throw;
}
@@ -210,6 +220,50 @@ SessionClient::run(int argc, char* argv[])
}
void
+SessionClient::interruptCallback(int)
+{
+ //
+ // Terminate the refresh thread, destroy the session and then
+ // destroy the communicator, followed by an exit. We have to call
+ // exit because main may be blocked in a cin >> s call which
+ // cannot be interrupted portably.
+ //
+ cleanup(true);
+
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
+SessionClient::cleanup(bool destroy)
+{
+ IceUtil::Mutex::Lock sync(_mutex);
+ if(_refresh)
+ {
+ _refresh->terminate();
+ _refresh->getThreadControl().join();
+ _refresh = 0;
+ }
+
+ if(destroy && _session)
+ {
+ _session->destroy();
+ _session = 0;
+ }
+}
+
+void
SessionClient::menu()
{
cout <<
diff --git a/cpp/demo/Ice/throughput/Client.cpp b/cpp/demo/Ice/throughput/Client.cpp
index 03bfd13aeec..a2c00c008a3 100644
--- a/cpp/demo/Ice/throughput/Client.cpp
+++ b/cpp/demo/Ice/throughput/Client.cpp
@@ -20,6 +20,7 @@ class ThroughputClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
@@ -36,6 +37,12 @@ main(int argc, char* argv[])
int
ThroughputClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
Ice::ObjectPrx base = communicator()->propertyToProxy("Throughput.Throughput");
ThroughputPrx throughput = ThroughputPrx::checkedCast(base);
if(!throughput)
@@ -378,6 +385,24 @@ ThroughputClient::run(int argc, char* argv[])
}
void
+ThroughputClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
ThroughputClient::menu()
{
cout <<
diff --git a/cpp/demo/Ice/value/Client.cpp b/cpp/demo/Ice/value/Client.cpp
index a375da519de..de4885f7f79 100644
--- a/cpp/demo/Ice/value/Client.cpp
+++ b/cpp/demo/Ice/value/Client.cpp
@@ -19,6 +19,7 @@ class ValueClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
};
int
@@ -31,6 +32,12 @@ main(int argc, char* argv[])
int
ValueClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
Ice::ObjectPrx base = communicator()->propertyToProxy("Value.Initial");
InitialPrx initial = InitialPrx::checkedCast(base);
if(!initial)
@@ -174,3 +181,21 @@ ValueClient::run(int argc, char* argv[])
return EXIT_SUCCESS;
}
+
+void
+ValueClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/IceBox/hello/Client.cpp b/cpp/demo/IceBox/hello/Client.cpp
index 17764a6a845..830f24aa7ef 100644
--- a/cpp/demo/IceBox/hello/Client.cpp
+++ b/cpp/demo/IceBox/hello/Client.cpp
@@ -18,6 +18,7 @@ class HelloClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
@@ -50,6 +51,12 @@ HelloClient::menu()
int
HelloClient::run(int argc, char* argv[])
{
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
HelloPrx twoway = HelloPrx::checkedCast(
communicator()->propertyToProxy("Hello.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false));
if(!twoway)
@@ -153,3 +160,21 @@ HelloClient::run(int argc, char* argv[])
return EXIT_SUCCESS;
}
+
+void
+HelloClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/demo/IceGrid/allocate/Client.cpp b/cpp/demo/IceGrid/allocate/Client.cpp
index b4df84f00c9..79b21842dfd 100644
--- a/cpp/demo/IceGrid/allocate/Client.cpp
+++ b/cpp/demo/IceGrid/allocate/Client.cpp
@@ -57,7 +57,7 @@ public:
private:
- IceGrid::SessionPrx _session;
+ const IceGrid::SessionPrx _session;
const IceUtil::Time _timeout;
bool _destroy;
};
@@ -69,11 +69,17 @@ class HelloClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
+ void cleanup();
void menu();
string trim(const string&);
+
+ IceUtil::Mutex _mutex;
+ IceGrid::SessionPrx _session;
+ SessionKeepAliveThreadPtr _keepAlive;
};
int
@@ -83,43 +89,25 @@ main(int argc, char* argv[])
return app.main(argc, argv, "config.client");
}
-void
-HelloClient::menu()
-{
- cout <<
- "usage:\n"
- "t: send greeting\n"
- "s: shutdown server\n"
- "x: exit\n"
- "?: help\n";
-}
-
-string
-HelloClient::trim(const string& s)
-{
- static const string delims = "\t\r\n ";
- string::size_type last = s.find_last_not_of(delims);
- if(last != string::npos)
- {
- return s.substr(s.find_first_not_of(delims), last+1);
- }
- return s;
-}
-
int
HelloClient::run(int argc, char* argv[])
{
int status = EXIT_SUCCESS;
- IceGrid::RegistryPrx registry =
- IceGrid::RegistryPrx::checkedCast(communicator()->stringToProxy("DemoIceGrid/Registry"));
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
+ IceGrid::RegistryPrx registry = IceGrid::RegistryPrx::checkedCast(
+ communicator()->stringToProxy("DemoIceGrid/Registry"));
if(!registry)
{
cerr << argv[0] << ": could not contact registry" << endl;
return EXIT_FAILURE;
}
- IceGrid::SessionPrx session;
while(true)
{
cout << "This demo accepts any user-id / password combination.\n";
@@ -136,7 +124,8 @@ HelloClient::run(int argc, char* argv[])
try
{
- session = registry->createSession(id, password);
+ IceUtil::Mutex::Lock sync(_mutex);
+ _session = registry->createSession(id, password);
break;
}
catch(const IceGrid::PermissionDeniedException& ex)
@@ -145,8 +134,11 @@ HelloClient::run(int argc, char* argv[])
}
}
- SessionKeepAliveThreadPtr keepAlive = new SessionKeepAliveThread(session, registry->getSessionTimeout() / 2);
- keepAlive->start();
+ {
+ IceUtil::Mutex::Lock sync(_mutex);
+ _keepAlive = new SessionKeepAliveThread(_session, registry->getSessionTimeout() / 2);
+ _keepAlive->start();
+ }
try
{
@@ -159,11 +151,11 @@ HelloClient::run(int argc, char* argv[])
HelloPrx hello;
try
{
- hello = HelloPrx::checkedCast(session->allocateObjectById(communicator()->stringToIdentity("hello")));
+ hello = HelloPrx::checkedCast(_session->allocateObjectById(communicator()->stringToIdentity("hello")));
}
catch(const IceGrid::ObjectNotRegisteredException&)
{
- hello = HelloPrx::checkedCast(session->allocateObjectByType("::Demo::Hello"));
+ hello = HelloPrx::checkedCast(_session->allocateObjectByType("::Demo::Hello"));
}
menu();
@@ -215,14 +207,71 @@ HelloClient::run(int argc, char* argv[])
status = EXIT_FAILURE;
}
+ cleanup();
+ return status;
+}
+
+void
+HelloClient::interruptCallback(int)
+{
+ cleanup();
+
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
+HelloClient::cleanup()
+{
+ IceUtil::Mutex::Lock sync(_mutex);
//
// Destroy the keepAlive thread and the sesion object otherwise
// the session will be kept allocated until the timeout occurs.
// Destroying the session will release all allocated objects.
//
- keepAlive->destroy();
- keepAlive->getThreadControl().join();
- session->destroy();
+ if(_keepAlive)
+ {
+ _keepAlive->destroy();
+ _keepAlive->getThreadControl().join();
+ _keepAlive = 0;
+ }
+ if(_session)
+ {
+ _session->destroy();
+ _session = 0;
+ }
+}
- return status;
+void
+HelloClient::menu()
+{
+ cout <<
+ "usage:\n"
+ "t: send greeting\n"
+ "s: shutdown server\n"
+ "x: exit\n"
+ "?: help\n";
+}
+
+string
+HelloClient::trim(const string& s)
+{
+ static const string delims = "\t\r\n ";
+ string::size_type last = s.find_last_not_of(delims);
+ if(last != string::npos)
+ {
+ return s.substr(s.find_first_not_of(delims), last+1);
+ }
+ return s;
}
diff --git a/cpp/demo/IceGrid/sessionActivation/Client.cpp b/cpp/demo/IceGrid/sessionActivation/Client.cpp
index d8fc48e65dc..b4e9f719f53 100644
--- a/cpp/demo/IceGrid/sessionActivation/Client.cpp
+++ b/cpp/demo/IceGrid/sessionActivation/Client.cpp
@@ -69,11 +69,17 @@ class HelloClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
+ void cleanup();
void menu();
string trim(const string&);
+
+ IceUtil::Mutex _mutex;
+ IceGrid::SessionPrx _session;
+ SessionKeepAliveThreadPtr _keepAlive;
};
int
@@ -83,32 +89,17 @@ main(int argc, char* argv[])
return app.main(argc, argv, "config.client");
}
-void
-HelloClient::menu()
-{
- cout <<
- "usage:\n"
- "t: send greeting\n"
- "x: exit\n"
- "?: help\n";
-}
-
-string
-HelloClient::trim(const string& s)
-{
- static const string delims = "\t\r\n ";
- string::size_type last = s.find_last_not_of(delims);
- if(last != string::npos)
- {
- return s.substr(s.find_first_not_of(delims), last+1);
- }
- return s;
-}
-
int
HelloClient::run(int argc, char* argv[])
{
int status = EXIT_SUCCESS;
+
+ //
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
IceGrid::RegistryPrx registry =
IceGrid::RegistryPrx::checkedCast(communicator()->stringToProxy("DemoIceGrid/Registry"));
if(!registry)
@@ -117,7 +108,6 @@ HelloClient::run(int argc, char* argv[])
return EXIT_FAILURE;
}
- IceGrid::SessionPrx session;
while(true)
{
cout << "This demo accepts any user-id / password combination.\n";
@@ -134,7 +124,8 @@ HelloClient::run(int argc, char* argv[])
try
{
- session = registry->createSession(id, password);
+ IceUtil::Mutex::Lock sync(_mutex);
+ _session = registry->createSession(id, password);
break;
}
catch(const IceGrid::PermissionDeniedException& ex)
@@ -143,12 +134,15 @@ HelloClient::run(int argc, char* argv[])
}
}
- SessionKeepAliveThreadPtr keepAlive = new SessionKeepAliveThread(session, registry->getSessionTimeout() / 2);
- keepAlive->start();
+ {
+ IceUtil::Mutex::Lock sync(_mutex);
+ _keepAlive = new SessionKeepAliveThread(_session, registry->getSessionTimeout() / 2);
+ _keepAlive->start();
+ }
try
{
- HelloPrx hello = HelloPrx::checkedCast(session->allocateObjectById(communicator()->stringToIdentity("hello")));
+ HelloPrx hello = HelloPrx::checkedCast(_session->allocateObjectById(communicator()->stringToIdentity("hello")));
menu();
@@ -205,15 +199,72 @@ HelloClient::run(int argc, char* argv[])
status = EXIT_FAILURE;
}
+ cleanup();
+
+ return status;
+}
+
+void
+HelloClient::interruptCallback(int)
+{
+ cleanup();
+
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
+HelloClient::cleanup()
+{
+ IceUtil::Mutex::Lock sync(_mutex);
//
// Destroy the keepAlive thread and the sesion object otherwise
// the session will be kept allocated until the timeout occurs.
// Destroying the session will release all allocated objects.
//
- keepAlive->destroy();
- keepAlive->getThreadControl().join();
- session->destroy();
+ if(_keepAlive)
+ {
+ _keepAlive->destroy();
+ _keepAlive->getThreadControl().join();
+ _keepAlive = 0;
+ }
+ if(_session)
+ {
+ _session->destroy();
+ _session = 0;
+ }
+}
- return status;
+void
+HelloClient::menu()
+{
+ cout <<
+ "usage:\n"
+ "t: send greeting\n"
+ "x: exit\n"
+ "?: help\n";
+}
+
+string
+HelloClient::trim(const string& s)
+{
+ static const string delims = "\t\r\n ";
+ string::size_type last = s.find_last_not_of(delims);
+ if(last != string::npos)
+ {
+ return s.substr(s.find_first_not_of(delims), last+1);
+ }
+ return s;
}
diff --git a/cpp/demo/IceGrid/simple/Client.cpp b/cpp/demo/IceGrid/simple/Client.cpp
index 13259587dfb..bf86e3ee294 100644
--- a/cpp/demo/IceGrid/simple/Client.cpp
+++ b/cpp/demo/IceGrid/simple/Client.cpp
@@ -19,6 +19,7 @@ class HelloClient : public Ice::Application
public:
virtual int run(int, char*[]);
+ virtual void interruptCallback(int);
private:
@@ -47,6 +48,12 @@ int
HelloClient::run(int argc, char* argv[])
{
//
+ // Since this is an interactive demo we want the custom interrupt
+ // callback to be called when the process is interrupted.
+ //
+ userCallbackOnInterrupt();
+
+ //
// First we try to connect to the object with the `hello'
// identity. If it's not registered with the registry, we
// search for an object with the ::Demo::Hello type.
@@ -108,3 +115,20 @@ HelloClient::run(int argc, char* argv[])
return EXIT_SUCCESS;
}
+void
+HelloClient::interruptCallback(int)
+{
+ try
+ {
+ communicator()->destroy();
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << appName() << ": " << ex << endl;
+ }
+ catch(...)
+ {
+ cerr << appName() << ": unknown exception" << endl;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/cpp/include/Ice/Application.h b/cpp/include/Ice/Application.h
index ca3cd658188..4f2c27300e0 100644
--- a/cpp/include/Ice/Application.h
+++ b/cpp/include/Ice/Application.h
@@ -38,6 +38,16 @@ public:
virtual int run(int, char*[]) = 0;
//
+ // Override this to provide a custom application interrupt
+ // hook. You must call userCallbackOnInterrupt for this method to
+ // be called. Note that the interruptCallback can be called
+ // concurrently with any other thread (including main) in your
+ // application and thus must take appropriate concurrency
+ // precautions.
+ //
+ virtual void interruptCallback(int);
+
+ //
// Return the application name, i.e., argv[0].
//
static const char* appName();
@@ -58,6 +68,7 @@ public:
static void destroyOnInterrupt();
static void shutdownOnInterrupt();
static void ignoreInterrupt();
+ static void userCallbackOnInterrupt();
//
// These methods can be used to temporarily block a signal and
@@ -81,7 +92,6 @@ public:
//
static bool interrupted();
-
#if defined(__SUNPRO_CC)
//
// Sun C++ 5.x does not like classes with no data members
diff --git a/cpp/src/Ice/Application.cpp b/cpp/src/Ice/Application.cpp
index 8bee23ebe60..dfc03f6949c 100644
--- a/cpp/src/Ice/Application.cpp
+++ b/cpp/src/Ice/Application.cpp
@@ -40,6 +40,7 @@ static CtrlCHandlerCallback _previousCallback = 0;
// only the main thread and CtrlCHandler threads are running.
//
static const char* _appName = 0;
+static Application* _application;
static CommunicatorPtr _communicator;
static CtrlCHandler* _ctrlCHandler = 0;
static bool _nohup = false;
@@ -62,7 +63,8 @@ const DWORD SIGHUP = CTRL_LOGOFF_EVENT;
// CtrlCHandler callbacks.
//
-static void holdInterruptCallback(int signal)
+static void
+holdInterruptCallback(int signal)
{
CtrlCHandlerCallback callback = 0;
{
@@ -89,7 +91,8 @@ static void holdInterruptCallback(int signal)
}
}
-static void destroyOnInterruptCallback(int signal)
+static void
+destroyOnInterruptCallback(int signal)
{
{
StaticMutex::Lock lock(_mutex);
@@ -151,7 +154,8 @@ static void destroyOnInterruptCallback(int signal)
}
-static void shutdownOnInterruptCallback(int signal)
+static void
+shutdownOnInterruptCallback(int signal)
{
{
StaticMutex::Lock lock(_mutex);
@@ -171,6 +175,7 @@ static void shutdownOnInterruptCallback(int signal)
_interrupted = true;
}
+ assert(_communicator != 0);
try
{
_communicator->shutdown();
@@ -209,6 +214,65 @@ static void shutdownOnInterruptCallback(int signal)
}
+static void
+userCallbackOnInterruptCallback(int signal)
+{
+ {
+ StaticMutex::Lock lock(_mutex);
+ if(_destroyed)
+ {
+ //
+ // Being destroyed by main thread
+ //
+ return;
+ }
+ if(_nohup && signal == SIGHUP)
+ {
+ return;
+ }
+ assert(!_callbackInProgress);
+ _callbackInProgress = true;
+ _interrupted = true;
+ }
+
+ assert(_application != 0);
+ try
+ {
+ _application->interruptCallback(signal);
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << _appName << " (while interrupting in response to signal " << signal
+ << "): " << ex << endl;
+ }
+ catch(const std::exception& ex)
+ {
+ cerr << _appName << " (while interrupting in response to signal " << signal
+ << "): std::exception: " << ex.what() << endl;
+ }
+ catch(const std::string& msg)
+ {
+ cerr << _appName << " (while interrupting in response to signal " << signal
+ << "): " << msg << endl;
+ }
+ catch(const char * msg)
+ {
+ cerr << _appName << " (while interrupting in response to signal " << signal
+ << "): " << msg << endl;
+ }
+ catch(...)
+ {
+ cerr << _appName << " (while interrupting in response to signal " << signal
+ << "): unknown exception" << endl;
+ }
+
+ {
+ StaticMutex::Lock lock(_mutex);
+ _callbackInProgress = false;
+ }
+ _condVar->signal();
+}
+
Ice::Application::Application()
{
@@ -319,6 +383,7 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat
_interrupted = false;
_appName = argv[0];
+ _application = this;
_communicator = initialize(argc, argv, initData);
_destroyed = false;
@@ -327,7 +392,6 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat
//
_nohup = (_communicator->getProperties()->getPropertyAsInt("Ice.Nohup") > 0);
-
//
// The default is to destroy when a signal is received.
//
@@ -361,8 +425,9 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat
}
//
- // Don't want any new interrupt
- // And at this point (post-run), it would not make sense to release a held signal to run shutdown or destroy.
+ // Don't want any new interrupt and at this point (post-run),
+ // it would not make sense to release a held signal to run
+ // shutdown or destroy.
//
ignoreInterrupt();
@@ -380,10 +445,12 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat
{
_destroyed = true;
//
- // And _communicator != 0, meaning will be destroyed next,
- // _destroyed = true also ensures that any remaining callback won't do anything
+ // And _communicator != 0, meaning will be destroyed
+ // next, _destroyed = true also ensures that any
+ // remaining callback won't do anything
//
}
+ _application = 0;
}
if(_communicator != 0)
@@ -424,6 +491,11 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat
return status;
}
+void
+Ice::Application::interruptCallback(int)
+{
+}
+
const char*
Ice::Application::appName()
{
@@ -438,11 +510,10 @@ Ice::Application::communicator()
void
Ice::Application::destroyOnInterrupt()
-{
+{
//
// if _ctrlCHandler == 0, it's really a bug in the caller
//
-
if(_ctrlCHandler != 0)
{
StaticMutex::Lock lock(_mutex); // we serialize all the interrupt-setting
@@ -498,6 +569,25 @@ Ice::Application::ignoreInterrupt()
}
void
+Ice::Application::userCallbackOnInterrupt()
+{
+ if(_ctrlCHandler != 0)
+ {
+ StaticMutex::Lock lock(_mutex); // we serialize all the interrupt-setting
+ if(_ctrlCHandler->getCallback() == holdInterruptCallback)
+ {
+ _released = true;
+ _ctrlCHandler->setCallback(userCallbackOnInterruptCallback);
+ _condVar->signal();
+ }
+ else
+ {
+ _ctrlCHandler->setCallback(userCallbackOnInterruptCallback);
+ }
+ }
+}
+
+void
Ice::Application::holdInterrupt()
{
if(_ctrlCHandler != 0)
diff --git a/java/demo/Freeze/library/Client.java b/java/demo/Freeze/library/Client.java
index 3105354d443..67b6af17477 100644
--- a/java/demo/Freeze/library/Client.java
+++ b/java/demo/Freeze/library/Client.java
@@ -9,9 +9,32 @@
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
return RunParser.runParser(appName(), args, communicator());
}
diff --git a/java/demo/Freeze/library/Collocated.java b/java/demo/Freeze/library/Collocated.java
index ec6beade155..8cb11e19a00 100644
--- a/java/demo/Freeze/library/Collocated.java
+++ b/java/demo/Freeze/library/Collocated.java
@@ -9,9 +9,32 @@
class LibraryCollocated extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
Ice.Properties properties = communicator().getProperties();
//
diff --git a/java/demo/Freeze/phonebook/Client.java b/java/demo/Freeze/phonebook/Client.java
index c4ec8377276..ede5856bcd4 100644
--- a/java/demo/Freeze/phonebook/Client.java
+++ b/java/demo/Freeze/phonebook/Client.java
@@ -9,9 +9,32 @@
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
return RunParser.runParser(appName(), args, communicator());
}
diff --git a/java/demo/Freeze/phonebook/Collocated.java b/java/demo/Freeze/phonebook/Collocated.java
index 825da566780..a02ba0a96f4 100644
--- a/java/demo/Freeze/phonebook/Collocated.java
+++ b/java/demo/Freeze/phonebook/Collocated.java
@@ -9,9 +9,32 @@
class PhoneBookCollocated extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
Ice.Properties properties = communicator().getProperties();
//
diff --git a/java/demo/Glacier2/callback/Client.java b/java/demo/Glacier2/callback/Client.java
index b1e90ce021c..b86e111c1cf 100644
--- a/java/demo/Glacier2/callback/Client.java
+++ b/java/demo/Glacier2/callback/Client.java
@@ -11,6 +11,22 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
private static void
menu()
{
@@ -30,6 +46,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
Ice.RouterPrx defaultRouter = communicator().getDefaultRouter();
if(defaultRouter == null)
{
diff --git a/java/demo/Ice/callback/Client.java b/java/demo/Ice/callback/Client.java
index 35a91f8b6ac..f382f6cbf66 100644
--- a/java/demo/Ice/callback/Client.java
+++ b/java/demo/Ice/callback/Client.java
@@ -11,6 +11,22 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
private static void
menu()
{
@@ -31,6 +47,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
CallbackSenderPrx twoway = CallbackSenderPrxHelper.checkedCast(
communicator().propertyToProxy("Callback.Client.CallbackServer").
ice_twoway().ice_timeout(-1).ice_secure(false));
diff --git a/java/demo/Ice/hello/Client.java b/java/demo/Ice/hello/Client.java
index df647df390e..67fd95e2d3e 100644
--- a/java/demo/Ice/hello/Client.java
+++ b/java/demo/Ice/hello/Client.java
@@ -11,6 +11,22 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
private static void
menu()
{
@@ -33,6 +49,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
HelloPrx twoway = HelloPrxHelper.checkedCast(
communicator().propertyToProxy("Hello.Proxy").ice_twoway().ice_timeout(-1).ice_secure(false));
if(twoway == null)
@@ -206,3 +229,4 @@ public class Client extends Ice.Application
System.exit(status);
}
}
+
diff --git a/java/demo/Ice/invoke/Client.java b/java/demo/Ice/invoke/Client.java
index 0ba48171d1c..1275ecaad12 100644
--- a/java/demo/Ice/invoke/Client.java
+++ b/java/demo/Ice/invoke/Client.java
@@ -30,9 +30,32 @@ public class Client extends Ice.Application
"?: help\n");
}
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
Ice.ObjectPrx obj = communicator().propertyToProxy("Printer.Proxy");
menu();
diff --git a/java/demo/Ice/nested/Client.java b/java/demo/Ice/nested/Client.java
index b16a183b257..60264585c7e 100644
--- a/java/demo/Ice/nested/Client.java
+++ b/java/demo/Ice/nested/Client.java
@@ -11,10 +11,40 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ /*
+ * For this demo we won't destroy the communicator since it has to
+ * wait for any outstanding invocations to complete which may take
+ * some time if the nesting level is exceeded.
+ *
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ */
+ }
+ }
+
public int
run(String[] args)
{
- NestedPrx nested = NestedPrxHelper.checkedCast(communicator().propertyToProxy("Nested.Client.NestedServer"));
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
+ NestedPrx nested = NestedPrxHelper.checkedCast(
+ communicator().propertyToProxy("Nested.Client.NestedServer"));
if(nested == null)
{
System.err.println("invalid proxy");
diff --git a/java/demo/Ice/session/Client.java b/java/demo/Ice/session/Client.java
index 5b5a0be67a1..0009a2fefec 100644
--- a/java/demo/Ice/session/Client.java
+++ b/java/demo/Ice/session/Client.java
@@ -11,6 +11,24 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ System.out.println("Hi");
+ cleanup(true);
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
static private class SessionRefreshThread extends Thread
{
SessionRefreshThread(Ice.Logger logger, long timeout, SessionPrx session)
@@ -76,6 +94,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
String name;
try
@@ -102,15 +127,17 @@ public class Client extends Ice.Application
return 1;
}
- SessionPrx session = factory.create(name);
- SessionRefreshThread refresh = new SessionRefreshThread(communicator().getLogger(), 5000, session);
- refresh.start();
-
+ synchronized(this)
+ {
+ _session = factory.create(name);
+ _refresh = new SessionRefreshThread(communicator().getLogger(), 5000, _session);
+ _refresh.start();
+ }
+
java.util.ArrayList hellos = new java.util.ArrayList();
menu();
-
try
{
boolean destroy = true;
@@ -149,7 +176,7 @@ public class Client extends Ice.Application
}
else if(line.equals("c"))
{
- hellos.add(session.createHello());
+ hellos.add(_session.createHello());
System.out.println("created hello object " + (hellos.size()-1));
}
else if(line.equals("s"))
@@ -177,26 +204,8 @@ public class Client extends Ice.Application
menu();
}
}
- //
- // The refresher thread must be terminated before destroy is
- // called, otherwise it might get ObjectNotExistException. refresh
- // is set to 0 so that if session->destroy() raises an exception
- // the thread will not be re-terminated and re-joined.
- //
- refresh.terminate();
- try
- {
- refresh.join();
- }
- catch(InterruptedException e)
- {
- }
- refresh = null;
- if(destroy)
- {
- session.destroy();
- }
+ cleanup(destroy);
if(shutdown)
{
factory.shutdown();
@@ -212,22 +221,39 @@ public class Client extends Ice.Application
}
finally
{
- if(refresh != null)
- {
- refresh.terminate();
- try
- {
- refresh.join();
- }
- catch(InterruptedException e)
- {
- }
- }
+ cleanup(true);
}
return 0;
}
+ synchronized private void
+ cleanup(boolean destroy)
+ {
+ //
+ // The refresher thread must be terminated before destroy is
+ // called, otherwise it might get ObjectNotExistException.
+ //
+ if(_refresh != null)
+ {
+ _refresh.terminate();
+ try
+ {
+ _refresh.join();
+ }
+ catch(InterruptedException e)
+ {
+ }
+ _refresh = null;
+ }
+
+ if(destroy && _session != null)
+ {
+ _session.destroy();
+ _session = null;
+ }
+ }
+
public static void
main(String[] args)
{
@@ -235,4 +261,7 @@ public class Client extends Ice.Application
int status = app.main("Client", args, "config.client");
System.exit(status);
}
+
+ private SessionRefreshThread _refresh = null;
+ private SessionPrx _session = null;
}
diff --git a/java/demo/Ice/throughput/Client.java b/java/demo/Ice/throughput/Client.java
index 99bfdcef97a..1d926a71b0a 100644
--- a/java/demo/Ice/throughput/Client.java
+++ b/java/demo/Ice/throughput/Client.java
@@ -11,6 +11,22 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
private static void
menu()
{
@@ -38,6 +54,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
Ice.ObjectPrx base = communicator().propertyToProxy("Throughput.Throughput");
ThroughputPrx throughput = ThroughputPrxHelper.checkedCast(base);
if(throughput == null)
diff --git a/java/demo/Ice/value/Client.java b/java/demo/Ice/value/Client.java
index 3ef39e8a35b..f33166da5fd 100644
--- a/java/demo/Ice/value/Client.java
+++ b/java/demo/Ice/value/Client.java
@@ -11,6 +11,22 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
private static void
readline(java.io.BufferedReader in)
{
@@ -27,6 +43,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
Ice.ObjectPrx base = communicator().propertyToProxy("Value.Initial");
InitialPrx initial = InitialPrxHelper.checkedCast(base);
if(initial == null)
diff --git a/java/demo/IceBox/hello/Client.java b/java/demo/IceBox/hello/Client.java
index cfa4701dd7c..6a7c1f5156a 100644
--- a/java/demo/IceBox/hello/Client.java
+++ b/java/demo/IceBox/hello/Client.java
@@ -11,6 +11,22 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
private void
menu()
{
@@ -29,6 +45,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
HelloPrx twoway = HelloPrxHelper.checkedCast(
communicator().propertyToProxy("Hello.Proxy").ice_twoway().ice_timeout(-1).ice_secure(false));
if(twoway == null)
diff --git a/java/demo/IceGrid/allocate/Client.java b/java/demo/IceGrid/allocate/Client.java
index a82004d6763..d8eb2e81b0d 100644
--- a/java/demo/IceGrid/allocate/Client.java
+++ b/java/demo/IceGrid/allocate/Client.java
@@ -11,6 +11,23 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ cleanup();
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
static private class SessionKeepAliveThread extends Thread
{
SessionKeepAliveThread(IceGrid.SessionPrx session, long timeout)
@@ -73,6 +90,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
int status = 0;
IceGrid.RegistryPrx registry =
IceGrid.RegistryPrxHelper.checkedCast(communicator().stringToProxy("DemoIceGrid/Registry"));
@@ -83,7 +107,6 @@ public class Client extends Ice.Application
}
java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
- IceGrid.SessionPrx session;
while(true)
{
System.out.println("This demo accepts any user-id / password combination.");
@@ -102,7 +125,10 @@ public class Client extends Ice.Application
try
{
- session = registry.createSession(id, pw);
+ synchronized(this)
+ {
+ _session = registry.createSession(id, pw);
+ }
break;
}
catch(IceGrid.PermissionDeniedException ex)
@@ -116,8 +142,11 @@ public class Client extends Ice.Application
}
}
- SessionKeepAliveThread keepAlive = new SessionKeepAliveThread(session, registry.getSessionTimeout() / 2);
- keepAlive.start();
+ synchronized(this)
+ {
+ _keepAlive = new SessionKeepAliveThread(_session, registry.getSessionTimeout() / 2);
+ _keepAlive.start();
+ }
try
{
@@ -132,11 +161,11 @@ public class Client extends Ice.Application
try
{
hello = HelloPrxHelper.checkedCast(
- session.allocateObjectById(communicator().stringToIdentity("hello")));
+ _session.allocateObjectById(communicator().stringToIdentity("hello")));
}
catch(IceGrid.ObjectNotRegisteredException ex)
{
- hello = HelloPrxHelper.checkedCast(session.allocateObjectByType("::Demo::Hello"));
+ hello = HelloPrxHelper.checkedCast(_session.allocateObjectByType("::Demo::Hello"));
}
menu();
@@ -197,22 +226,36 @@ public class Client extends Ice.Application
status = 1;
}
+ cleanup();
+
+ return status;
+ }
+
+ synchronized void
+ cleanup()
+ {
//
// Destroy the keepAlive thread and the sesion object otherwise
// the session will be kept allocated until the timeout occurs.
// Destroying the session will release all allocated objects.
//
- keepAlive.terminate();
- try
+ if(_keepAlive != null)
{
- keepAlive.join();
+ _keepAlive.terminate();
+ try
+ {
+ _keepAlive.join();
+ }
+ catch(InterruptedException e)
+ {
+ }
+ _keepAlive = null;
}
- catch(InterruptedException e)
+ if(_session != null)
{
+ _session.destroy();
+ _session = null;
}
- session.destroy();
-
- return status;
}
public static void
@@ -222,4 +265,7 @@ public class Client extends Ice.Application
int status = app.main("Client", args, "config.client");
System.exit(status);
}
+
+ SessionKeepAliveThread _keepAlive;
+ IceGrid.SessionPrx _session;
}
diff --git a/java/demo/IceGrid/sessionActivation/Client.java b/java/demo/IceGrid/sessionActivation/Client.java
index 7b89d4b16f9..3449068b79a 100644
--- a/java/demo/IceGrid/sessionActivation/Client.java
+++ b/java/demo/IceGrid/sessionActivation/Client.java
@@ -11,6 +11,23 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ cleanup();
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
static private class SessionKeepAliveThread extends Thread
{
SessionKeepAliveThread(IceGrid.SessionPrx session, long timeout)
@@ -72,6 +89,13 @@ public class Client extends Ice.Application
public int
run(String[] args)
{
+ //
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
int status = 0;
IceGrid.RegistryPrx registry =
IceGrid.RegistryPrxHelper.checkedCast(communicator().stringToProxy("DemoIceGrid/Registry"));
@@ -82,7 +106,6 @@ public class Client extends Ice.Application
}
java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
- IceGrid.SessionPrx session;
while(true)
{
System.out.println("This demo accepts any user-id / password combination.");
@@ -101,7 +124,10 @@ public class Client extends Ice.Application
try
{
- session = registry.createSession(id, pw);
+ synchronized(this)
+ {
+ _session = registry.createSession(id, pw);
+ }
break;
}
catch(IceGrid.PermissionDeniedException ex)
@@ -115,13 +141,16 @@ public class Client extends Ice.Application
}
}
- SessionKeepAliveThread keepAlive = new SessionKeepAliveThread(session, registry.getSessionTimeout() / 2);
- keepAlive.start();
+ synchronized(this)
+ {
+ _keepAlive = new SessionKeepAliveThread(_session, registry.getSessionTimeout() / 2);
+ _keepAlive.start();
+ }
try
{
HelloPrx hello = HelloPrxHelper.checkedCast(
- session.allocateObjectById(communicator().stringToIdentity("hello")));
+ _session.allocateObjectById(communicator().stringToIdentity("hello")));
menu();
@@ -182,22 +211,36 @@ public class Client extends Ice.Application
status = 1;
}
+ cleanup();
+
+ return status;
+ }
+
+ synchronized void
+ cleanup()
+ {
//
// Destroy the keepAlive thread and the sesion object otherwise
// the session will be kept allocated until the timeout occurs.
// Destroying the session will release all allocated objects.
//
- keepAlive.terminate();
- try
+ if(_keepAlive != null)
{
- keepAlive.join();
+ _keepAlive.terminate();
+ try
+ {
+ _keepAlive.join();
+ }
+ catch(InterruptedException e)
+ {
+ }
+ _keepAlive = null;
}
- catch(InterruptedException e)
+ if(_session != null)
{
+ _session.destroy();
+ _session = null;
}
- session.destroy();
-
- return status;
}
public static void
@@ -207,4 +250,7 @@ public class Client extends Ice.Application
int status = app.main("Client", args, "config.client");
System.exit(status);
}
+
+ SessionKeepAliveThread _keepAlive;
+ IceGrid.SessionPrx _session;
}
diff --git a/java/demo/IceGrid/simple/Client.java b/java/demo/IceGrid/simple/Client.java
index 1c9333080ba..d5ae5065837 100644
--- a/java/demo/IceGrid/simple/Client.java
+++ b/java/demo/IceGrid/simple/Client.java
@@ -11,6 +11,22 @@ import Demo.*;
public class Client extends Ice.Application
{
+ class ShutdownHook extends Thread
+ {
+ public void
+ run()
+ {
+ try
+ {
+ communicator().destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
private void
menu()
{
@@ -26,6 +42,13 @@ public class Client extends Ice.Application
run(String[] args)
{
//
+ // Since this is an interactive demo we want to clear the
+ // Application installed interrupt callback and install our
+ // own shutdown hook.
+ //
+ setInterruptHook(new ShutdownHook());
+
+ //
// First we try to connect to the object with the `hello'
// identity. If it's not registered with the registry, we
// search for an object with the ::Demo::Hello type.
diff --git a/java/src/Ice/Application.java b/java/src/Ice/Application.java
index 6735596e912..b27315becef 100644
--- a/java/src/Ice/Application.java
+++ b/java/src/Ice/Application.java
@@ -135,6 +135,7 @@ public abstract class Application
status = 1;
}
+ // This clears any set interrupt.
defaultInterrupt();
synchronized(_mutex)
@@ -149,6 +150,7 @@ public abstract class Application
{
}
}
+
if(_destroyed)
{
_communicator = null;
@@ -157,8 +159,9 @@ public abstract class Application
{
_destroyed = true;
//
- // And _communicator != null, meaning will be destroyed next,
- // _destroyed = true also ensures that any remaining callback won't do anything
+ // And _communicator != null, meaning will be
+ // destroyed next, _destroyed = true also ensures that
+ // any remaining callback won't do anything
//
}
}
@@ -186,14 +189,9 @@ public abstract class Application
synchronized(_mutex)
{
- if(_destroyHook != null)
- {
- _destroyHook.done();
- }
-
- if(_shutdownHook != null)
+ if(_appHook != null)
{
- _shutdownHook.done();
+ _appHook.done();
}
}
@@ -232,43 +230,20 @@ public abstract class Application
synchronized(_mutex)
{
//
- // Remove the shutdown hook it's set.
+ // As soon as the destroy hook ends all the threads are
+ // terminated. So the destroy hook will join the current
+ // thread before to end.
//
- if(_shutdownHook != null)
+ try
{
- try
- {
- Runtime.getRuntime().removeShutdownHook(_shutdownHook);
- _shutdownHook.done();
- _shutdownHook = null;
- }
- catch(java.lang.IllegalStateException ex)
- {
- //
- // Expected if we are in the process of shutting down.
- //
- }
+ changeHook(new DestroyHook());
}
-
- if(_destroyHook == null)
+ catch(java.lang.IllegalStateException ex)
{
- //
- // As soon as the destroy hook ends all the threads are
- // terminated. So the destroy hook will join the current
- // thread before to end.
- //
- _destroyHook = new DestroyHook();
- try
- {
- Runtime.getRuntime().addShutdownHook(_destroyHook);
- }
- catch(java.lang.IllegalStateException ex)
- {
- if(_communicator != null)
- {
- _communicator.destroy();
- }
- }
+ if(_communicator != null)
+ {
+ _communicator.destroy();
+ }
}
}
}
@@ -279,85 +254,54 @@ public abstract class Application
synchronized(_mutex)
{
//
- // Remove the destroy hook if it's set.
+ // As soon as the shutdown hook ends all the threads are
+ // terminated. So the shutdown hook will join the current
+ // thread before to end.
//
- if(_destroyHook != null)
+ try
{
- try
- {
- Runtime.getRuntime().removeShutdownHook(_destroyHook);
- _destroyHook.done();
- _destroyHook = null;
- }
- catch(java.lang.IllegalStateException ex)
- {
- //
- // Expected if we are in the process of shutting down.
- //
- }
+ changeHook(new ShutdownHook());
}
-
- if(_shutdownHook == null)
+ catch(java.lang.IllegalStateException ex)
{
- //
- // As soon as the shutdown hook ends all the threads are
- // terminated. So the shutdown hook will join the current
- // thread before to end.
- //
- _shutdownHook = new ShutdownHook();
- try
- {
- Runtime.getRuntime().addShutdownHook(_shutdownHook);
- }
- catch(java.lang.IllegalStateException ex)
- {
- if(_communicator != null)
- {
- _communicator.shutdown();
- }
- }
+ if(_communicator != null)
+ {
+ _communicator.shutdown();
+ }
}
}
}
-
+
+ //
+ // Install a custom shutdown hook. This hook is registered as a
+ // shutdown hook and should do whatever is necessary to terminate
+ // the application. Note that this runs as a shutdown hook so the
+ // code must obey the same rules as a shutdown hook (specifically
+ // don't call exit!). The shutdown and destroy shutdown interrupts
+ // are cleared. This hook is automatically unregistered after
+ // Application.run() returns.
+ //
public static void
- defaultInterrupt()
+ setInterruptHook(java.lang.Thread newHook) // Pun intended.
{
- synchronized(_mutex)
+ try
{
- if(_shutdownHook != null)
- {
- try
- {
- Runtime.getRuntime().removeShutdownHook(_shutdownHook);
- _shutdownHook.done();
- _shutdownHook = null;
- }
- catch(java.lang.IllegalStateException ex)
- {
- //
- // Expected if we are in the process of shutting down.
- //
- }
- }
-
- if(_destroyHook != null)
- {
- try
- {
- Runtime.getRuntime().removeShutdownHook(_destroyHook);
- _destroyHook.done();
- _destroyHook = null;
- }
- catch(java.lang.IllegalStateException ex)
- {
- //
- // Expected if we are in the process of shutting down.
- //
- }
- }
+ changeHook(new CustomHook(newHook));
+ }
+ catch(java.lang.IllegalStateException ex)
+ {
+ // Ignore.
}
}
+
+ //
+ // This clears any shutdown hooks including any custom hook.
+ //
+ public static void
+ defaultInterrupt()
+ {
+ changeHook(null);
+ }
public static boolean
interrupted()
@@ -368,6 +312,42 @@ public abstract class Application
}
}
+ private static void
+ changeHook(AppHook newHook)
+ {
+ synchronized(_mutex)
+ {
+ //
+ // Remove any existing shutdown hooks.
+ //
+ try
+ {
+ if(_appHook != null)
+ {
+ Runtime.getRuntime().removeShutdownHook(_appHook);
+ _appHook.done();
+ _appHook = null;
+ }
+ }
+ catch(java.lang.IllegalStateException ex)
+ {
+ //
+ // Expected if we are in the process of shutting down.
+ //
+ }
+
+ //
+ // Note that we let the IllegalStateException propogate
+ // out if necessary.
+ //
+ if(newHook != null)
+ {
+ Runtime.getRuntime().addShutdownHook(newHook);
+ _appHook = newHook;
+ }
+ }
+ }
+
private static boolean
setCallbackInProgress(boolean destroy)
{
@@ -397,13 +377,24 @@ public abstract class Application
}
}
- static class DestroyHook extends Thread
+ static class AppHook extends Thread
{
- DestroyHook()
+ void
+ done()
{
- _done = false;
+ synchronized(_doneMutex)
+ {
+ _done = true;
+ _doneMutex.notify();
+ }
}
+ protected boolean _done = false;
+ protected java.lang.Object _doneMutex = new java.lang.Object();
+ }
+
+ static class DestroyHook extends AppHook
+ {
public void
run()
{
@@ -434,28 +425,10 @@ public abstract class Application
}
}
}
-
- void
- done()
- {
- synchronized(_doneMutex)
- {
- _done = true;
- _doneMutex.notify();
- }
- }
-
- private boolean _done;
- private java.lang.Object _doneMutex = new java.lang.Object();
}
- static class ShutdownHook extends Thread
+ static class ShutdownHook extends AppHook
{
- ShutdownHook()
- {
- _done = false;
- }
-
public void
run()
{
@@ -486,25 +459,45 @@ public abstract class Application
}
}
}
+ }
- void
- done()
+ // Although this class doesn't actually use any of the AppHook
+ // done stuff, its more trouble than its worth to add all of the
+ // code necessary to support another hook member variable and
+ // support code.
+ static class CustomHook extends AppHook
+ {
+ CustomHook(Thread hook)
+ {
+ _hook = hook;
+ }
+
+ public void
+ run()
{
synchronized(_doneMutex)
{
- _done = true;
- _doneMutex.notify();
+ if(!setCallbackInProgress(false))
+ {
+ return;
+ }
+
+ _hook.run();
+
+ clearCallbackInProgress();
+
+ //
+ // Don't bother to join with main, we're done.
+ //
}
}
- private boolean _done;
- private java.lang.Object _doneMutex = new java.lang.Object();
+ private Thread _hook;
}
private static String _appName;
private static Communicator _communicator;
- private static DestroyHook _destroyHook;
- private static ShutdownHook _shutdownHook;
+ private static AppHook _appHook;
private static java.lang.Object _mutex = new java.lang.Object();
private static boolean _callbackInProgress = false;
private static boolean _destroyed = false;