diff options
author | Damian Minkov <damencho@jitsi.org> | 2012-10-05 12:31:11 +0000 |
---|---|---|
committer | Damian Minkov <damencho@jitsi.org> | 2012-10-05 12:31:11 +0000 |
commit | 21c7757e23a6f4ae2daa42b74e53e1f693c9aa0e (patch) | |
tree | f7b7ec24b6327181fda096b104ffd49ca88fe528 /src/net/java/sip/communicator | |
parent | 19d2276dd4ff5e3458b9aafd876aa38391feeac5 (diff) | |
download | jitsi-21c7757e23a6f4ae2daa42b74e53e1f693c9aa0e.zip jitsi-21c7757e23a6f4ae2daa42b74e53e1f693c9aa0e.tar.gz jitsi-21c7757e23a6f4ae2daa42b74e53e1f693c9aa0e.tar.bz2 |
Updates sysactivity handling QUERY_ENDSESSION and ENDSESSION events. Adds bundle that listens for the new events to handle clean shutdown.
Diffstat (limited to 'src/net/java/sip/communicator')
7 files changed, 334 insertions, 4 deletions
diff --git a/src/net/java/sip/communicator/impl/shutdowntimeout/ShutdownTimeout.java b/src/net/java/sip/communicator/impl/shutdowntimeout/ShutdownTimeout.java index e97cfb4..ea8cac8 100644 --- a/src/net/java/sip/communicator/impl/shutdowntimeout/ShutdownTimeout.java +++ b/src/net/java/sip/communicator/impl/shutdowntimeout/ShutdownTimeout.java @@ -30,9 +30,15 @@ public class ShutdownTimeout = 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 class ShutdownTimeout { 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){ diff --git a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityEventDispatcher.java b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityEventDispatcher.java index 8e091a5..4255eb7 100644 --- a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityEventDispatcher.java +++ b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityEventDispatcher.java @@ -117,6 +117,25 @@ public class SystemActivityEventDispatcher } /** + * 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. * * @param evt the <tt>SystemActivityEvent</tt> that we'd like delivered to diff --git a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotifications.java b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotifications.java index b7682c5..4f207e6 100644 --- a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotifications.java +++ b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotifications.java @@ -69,6 +69,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.
*/
private static Logger logger = Logger.getLogger(
diff --git a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java index e8891ad..67ec098 100644 --- a/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java +++ b/src/net/java/sip/communicator/impl/sysactivity/SystemActivityNotificationsServiceImpl.java @@ -278,6 +278,30 @@ public class SystemActivityNotificationsServiceImpl 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)
diff --git a/src/net/java/sip/communicator/plugin/windowscleanshutdown/CleanShutdownActivator.java b/src/net/java/sip/communicator/plugin/windowscleanshutdown/CleanShutdownActivator.java new file mode 100644 index 0000000..7c64243 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/windowscleanshutdown/CleanShutdownActivator.java @@ -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; + } + } +} diff --git a/src/net/java/sip/communicator/plugin/windowscleanshutdown/cleanshutdown.manifest.mf b/src/net/java/sip/communicator/plugin/windowscleanshutdown/cleanshutdown.manifest.mf new file mode 100644 index 0000000..25db59f --- /dev/null +++ b/src/net/java/sip/communicator/plugin/windowscleanshutdown/cleanshutdown.manifest.mf @@ -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 diff --git a/src/net/java/sip/communicator/service/sysactivity/event/SystemActivityEvent.java b/src/net/java/sip/communicator/service/sysactivity/event/SystemActivityEvent.java index 49494b0..36f85b9 100644 --- a/src/net/java/sip/communicator/service/sysactivity/event/SystemActivityEvent.java +++ b/src/net/java/sip/communicator/service/sysactivity/event/SystemActivityEvent.java @@ -87,6 +87,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.
*/
private final int eventID;
|