Updates sysactivity handling QUERY_ENDSESSION and ENDSESSION events. Adds bundle that listens for the new events to handle clean shutdown.

cusax-fix
Damian Minkov 13 years ago
parent 19d2276dd4
commit 21c7757e23

@ -439,6 +439,12 @@
<include name="logging.properties" />
</fileset>
</copy>
<!-- Add the windows specific bundle path in the felix.client.run.properties file -->
<echo file="${light.dir}/lib/felix.client.run.properties"
append="true">felix.auto.start.14= reference:file:sc-bundles/windows-clean-shutdown.jar
</echo>
<mkdir dir="${light.dir}/lib/bundle" />
<copy todir="${light.dir}/lib/bundle" overwrite="true">
<fileset dir="${sc.basedir}/lib/bundle">

@ -396,6 +396,18 @@ HRESULT callback(UINT Msg, WPARAM wParam, LPARAM lParam)
return TRUE;
}
}
else if (Msg == WM_QUERYENDSESSION)
{
notify(net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_QUERY_ENDSESSION);
return TRUE;
}
else if (Msg == WM_ENDSESSION && wParam == TRUE)
{
// we fire the message only if we are really ending the session
// is wParam is False means someone has canceled the shutdown/logoff
notify(net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_ENDSESSION);
return TRUE;
}
jvm->DetachCurrentThread();

@ -29,7 +29,10 @@ extern "C" {
#define net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_NETWORK_CHANGE 9L
#undef net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_DNS_CHANGE
#define net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_DNS_CHANGE 10L
#undef net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_QUERY_ENDSESSION
#define net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_QUERY_ENDSESSION 11L
#undef net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_ENDSESSION
#define net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications_NOTIFY_ENDSESSION 12L
/*
* Class: net_java_sip_communicator_impl_sysactivity_SystemActivityNotifications
* Method: allocAndInit

@ -29,10 +29,16 @@ public class ShutdownTimeout
private static final Logger logger
= Logger.getLogger(ShutdownTimeout.class);
/**
* The system property which can be used to set custom timeout.
*/
public static String SHUTDOWN_TIMEOUT_PROP =
"org.jitsi.shutdown.SHUTDOWN_TIMEOUT";
/**
* The number of miliseconds that we wait before we force a shutdown.
*/
public static final long SHUTDOWN_TIMEOUT = 15000;//ms
public static final long SHUTDOWN_TIMEOUT_DEFAULT = 3000;//ms
/**
* The code that we exit with if the application is not down in 15 seconds.
@ -72,11 +78,31 @@ public void run()
{
synchronized(this)
{
try{
try
{
long shutDownTimeout = SHUTDOWN_TIMEOUT_DEFAULT;
// check for custom value available through system
// property
try
{
String shutdownCustomValue =
System.getProperty(SHUTDOWN_TIMEOUT_PROP);
if(shutdownCustomValue != null
&& shutdownCustomValue.length() > 0)
{
shutDownTimeout =
Long.valueOf(shutdownCustomValue);
}
}
catch(Throwable t){}
if (logger.isTraceEnabled())
logger.trace("Starting shutdown countdown of "
+ SHUTDOWN_TIMEOUT + "ms.");
wait(SHUTDOWN_TIMEOUT);
+ shutDownTimeout + "ms.");
wait(shutDownTimeout);
logger.error("Failed to gently shutdown. Forcing exit.");
System.exit(SYSTEM_EXIT_CODE);
}catch (InterruptedException ex){

@ -116,6 +116,25 @@ protected void fireSystemActivityEvent(SystemActivityEvent evt)
fireSystemActivityEvent(evt, 0);
}
/**
* Delivers the specified event to all registered listeners. Without
* using the thread, but delivering them in the calling thread.
*
* @param evt the <tt>SystemActivityEvent</tt> that we'd like delivered to
* all registered message listeners.
*/
protected void fireSystemActivityEventCurrentThread(SystemActivityEvent evt)
{
List<SystemActivityChangeListener> listenersCopy = new ArrayList
<SystemActivityChangeListener>(listeners);
for (int i = 0; i < listenersCopy.size(); i++)
{
fireSystemActivityEvent(
evt,
listenersCopy.get(i));
}
}
/**
* Delivers the specified event to all registered listeners.
*

@ -68,6 +68,18 @@ public class SystemActivityNotifications
*/
public static final int NOTIFY_DNS_CHANGE = 10;
/**
* Notifies for start of process of ending desktop session,
* logoff or shutdown.
*/
public static final int NOTIFY_QUERY_ENDSESSION = 11;
/**
* All processes have been informed about ending session, now notify for
* the actual end session.
*/
public static final int NOTIFY_ENDSESSION = 12;
/**
* The logger.
*/

@ -278,6 +278,30 @@ public void notify(int type)
SystemActivityEvent.EVENT_DNS_CHANGE);
break;
}
case SystemActivityNotifications.NOTIFY_QUERY_ENDSESSION :
{
// both events QUERY_ENDSESSION and ENDSESSION
// depend on the result one after another
// we don't put them in new thread in order to give control
// in the bundles using this events.
evt = new SystemActivityEvent(this,
SystemActivityEvent.EVENT_QUERY_ENDSESSION);
eventDispatcher.fireSystemActivityEventCurrentThread(evt);
return;
}
case SystemActivityNotifications.NOTIFY_ENDSESSION :
{
// both events QUERY_ENDSESSION and ENDSESSION
// depend on the result one after another
// we don't put them in new thread in order to give control
// in the bundles using this events.
evt = new SystemActivityEvent(this,
SystemActivityEvent.EVENT_ENDSESSION);
eventDispatcher.fireSystemActivityEventCurrentThread(evt);
return;
}
}
if (evt != null)

@ -0,0 +1,224 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.windowscleanshutdown;
import net.java.sip.communicator.service.shutdown.*;
import net.java.sip.communicator.service.sysactivity.*;
import net.java.sip.communicator.service.sysactivity.event.*;
import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
import java.util.concurrent.*;
/**
* Tries to cleanly close the application on shutdown/logoff. The events used
* here are only available on windows.
*
* If the application is still running once end session event is received
* and we have give it time (currently 3 sec.) we System.exit() the application.
*
* @author Emil Ivov
*/
public class CleanShutdownActivator
implements BundleActivator, ServiceListener
{
private static final Logger logger
= Logger.getLogger(CleanShutdownActivator.class);
/**
* Used to wait for stop.
*/
final CountDownLatch synchShutdown = new CountDownLatch(1);
/**
* Our context.
*/
private BundleContext context;
/**
* The system activity service.
*/
SystemActivityNotificationsService sysActivityService = null;
/**
* Bundle activator start method.
*
* @throws Exception If this method throws an exception
* (which won't happen).
*/
public void start(final BundleContext context)
throws Exception
{
this.context = context;
logger.info("Starting the CleanShutdown service.");
handleNewSystemActivityNotificationsService(
getSystemActivityNotificationsService(context));
// if missing will wait for it
if(sysActivityService == null)
context.addServiceListener(this);
}
/**
* Called when this bundle is stopped so the Framework can perform the
* bundle-specific activities necessary to stop the bundle.
*
* @param context The execution context of the bundle being stopped.
* @throws Exception If this method throws an exception, the bundle is
* still marked as stopped, and the Framework will remove the bundle's
* listeners, unregister all services registered by the bundle, and
* release all services used by the bundle.
*/
public void stop(BundleContext context)
throws Exception
{
// stop received.
synchShutdown.countDown();
}
/**
* Gets a reference to a <code>ShutdownService</code> implementation
* currently registered in the bundle context of the active
* <code>OsDependentActivator</code> instance.
* <p>
* The returned reference to <code>ShutdownService</code> is not being
* cached.
* </p>
*
* @return reference to a <code>ShutdownService</code> implementation
* currently registered in the bundle context of the active
* <code>OsDependentActivator</code> instance
*/
private ShutdownService getShutdownService()
{
return(ShutdownService)context.getService(
context.getServiceReference(ShutdownService.class.getName()));
}
/**
* Gets a reference to a <code>SystemActivityNotificationsService</code>
* implementation currently registered in the bundle context.
* <p>
* The returned reference to <code>SystemActivityNotificationsService</code>
* is not being cached.
* </p>
*
* @param context the bundle context.
* @return reference to a <code>SystemActivityNotificationsService</code>
* implementation currently registered in the bundle context.
*/
public static SystemActivityNotificationsService
getSystemActivityNotificationsService(BundleContext context)
{
ServiceReference ref =
context.getServiceReference(
SystemActivityNotificationsService.class.getName());
if(ref == null)
return null;
else
return
(SystemActivityNotificationsService)
context.getService(ref);
}
/**
* Saves the reference for the service and
* add a listener if the desired events are supported. Or start
* the checking thread otherwise.
* @param newService the service
*/
private void handleNewSystemActivityNotificationsService
(SystemActivityNotificationsService newService)
{
sysActivityService = newService;
if(newService != null)
newService.addSystemActivityChangeListener(
new SystemActivityChangeListener()
{
public void activityChanged(SystemActivityEvent event)
{
if(event.getEventID()
== SystemActivityEvent.EVENT_QUERY_ENDSESSION)
{
// instruct the shutdown timeout to
// wait only 3 secs.
System.setProperty(
"org.jitsi.shutdown.SHUTDOWN_TIMEOUT",
"3000");
getShutdownService().beginShutdown();
// just wait a moment, or till we are stopped
try
{
synchronized(this)
{
synchShutdown.await(1500,
TimeUnit.MILLISECONDS);
}
}
catch(Throwable t)
{}
}
else if(event.getEventID()
== SystemActivityEvent.EVENT_ENDSESSION)
{
try
{
// wait till we are stopped or forced stopped
synchShutdown.await();
}
catch(Throwable t)
{}
}
}
});
}
/**
* When new SystemActivityNotificationsService
* is registered we add needed listeners.
*
* @param serviceEvent ServiceEvent
*/
public void serviceChanged(ServiceEvent serviceEvent)
{
ServiceReference serviceRef = serviceEvent.getServiceReference();
// if the event is caused by a bundle being stopped, we don't want to
// know we are shutting down
if (serviceRef.getBundle().getState() == Bundle.STOPPING)
{
return;
}
Object sService = context
.getService(serviceRef);
if(sService instanceof SystemActivityNotificationsService)
{
switch (serviceEvent.getType())
{
case ServiceEvent.REGISTERED:
handleNewSystemActivityNotificationsService(
(SystemActivityNotificationsService)sService);
break;
case ServiceEvent.UNREGISTERING:
//((SystemActivityNotificationsService)sService)
// .removeSystemActivityChangeListener(this);
break;
}
return;
}
}
}

@ -0,0 +1,12 @@
Bundle-Activator: net.java.sip.communicator.plugin.windowscleanshutdown.CleanShutdownActivator
Bundle-Name: CleanShutdownBundle
Bundle-Description: A bundle that makes sure that when closed Jitsi will exit cleanly.
Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
org.jitsi.service.configuration,
net.java.sip.communicator.service.shutdown,
net.java.sip.communicator.service.sysactivity,
net.java.sip.communicator.service.sysactivity.event,
net.java.sip.communicator.util

@ -86,6 +86,19 @@ public class SystemActivityEvent
*/
public static final int EVENT_DNS_CHANGE = 12;
/**
* Informing that the machine is logging of or shutting down.
*/
public static final int EVENT_QUERY_ENDSESSION = 13;
/**
* The log off or shutdown is in process for us, no matter
* what other process has replied, whether one of them has canceled
* or not the current end of session. It's like that cause we have answered
* that we will shutdown.
*/
public static final int EVENT_ENDSESSION = 14;
/**
* The type of the event.
*/

Loading…
Cancel
Save