/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.plugin.update;
import java.util.*;
import java.util.concurrent.*;
import net.java.sip.communicator.service.browserlauncher.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.shutdown.*;
import net.java.sip.communicator.service.update.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
import org.jitsi.service.configuration.*;
import org.jitsi.util.*;
import org.osgi.framework.*;
/**
* Implements <tt>BundleActivator</tt> for the update plug-in.
*
* @author Damian Minkov
* @author Lyubomir Marinov
*/
public class UpdateActivator
extends AbstractServiceDependentActivator
{
/**
* The <tt>Logger</tt> used by the <tt>UpdateActivator</tt> class and its
* instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(UpdateActivator.class);
/**
* The name of the configuration property which indicates whether the
* checking for updates on application startup is enabled.
*/
private static final String UPDATE_ENABLED
= "net.java.sip.communicator.plugin.updatechecker.ENABLED";
/**
* The name of the configuration property which indicates whether the
* "checking for updates" menu entry is disabled.
*/
private static final String CHECK_FOR_UPDATES_MENU_DISABLED_PROP
= "net.java.sip.communicator.plugin.update.checkforupdatesmenu.DISABLED";
/**
* The name of the configuration property which indicates whether the client
* should automatically check for updates each day or not.
*/
private static final String CHECK_FOR_UPDATES_DAILY_ENABLED_PROP =
"net.java.sip.communicator.plugin.update.checkforupdatesmenu.daily.ENABLED";
/**
* The name of the configuration property which indicates the hour that
* the client should check for updates (if daily update checking is enabled)
*/
private static final String CHECK_FOR_UPDATES_DAILY_TIME_PROP =
"net.java.sip.communicator.plugin.update.checkforupdatesmenu.daily.HOUR";
/**
* Reference to the <tt>BrowserLauncherService</tt>.
*/
private static BrowserLauncherService browserLauncher;
/**
* The <tt>BundleContext</tt> in which the one and only
* <tt>UpdateActivator</tt> instance of the update plug-in has been started.
*/
static BundleContext bundleContext;
/**
* Reference to the <tt>ConfigurationService</tt>.
*/
private static ConfigurationService configuration;
/**
* Reference to the <tt>UIService</tt>.
*/
private static UIService uiService;
/**
* The update service.
*/
private static UpdateService updateService;
/**
* A scheduler to check for updates once a day
*/
private ScheduledExecutorService mUpdateExecutor = null;
/**
* Returns the <tt>BrowserLauncherService</tt> obtained from the bundle
* context.
* @return the <tt>BrowserLauncherService</tt> obtained from the bundle
* context
*/
static BrowserLauncherService getBrowserLauncher()
{
if (browserLauncher == null)
{
browserLauncher
= ServiceUtils.getService(
bundleContext,
BrowserLauncherService.class);
}
return browserLauncher;
}
/**
* Returns the <tt>ConfigurationService</tt> obtained from the bundle
* context.
*
* @return the <tt>ConfigurationService</tt> obtained from the bundle
* context
*/
static ConfigurationService getConfiguration()
{
if (configuration == null)
{
configuration
= ServiceUtils.getService(
bundleContext,
ConfigurationService.class);
}
return configuration;
}
/**
* Gets a reference to a <code>ShutdownService</code> implementation
* currently registered in the bundle context of the active
* <code>UpdateCheckActivator</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>UpdateCheckActivator</code> instance
*/
static ShutdownService getShutdownService()
{
return ServiceUtils.getService(bundleContext, ShutdownService.class);
}
/**
* Returns a reference to the UIService implementation currently registered
* in the bundle context or null if no such implementation was found.
*
* @return a reference to a UIService implementation currently registered
* in the bundle context or null if no such implementation was found.
*/
static UIService getUIService()
{
if(uiService == null)
uiService = ServiceUtils.getService(bundleContext, UIService.class);
return uiService;
}
/**
* The dependent service is available and the bundle will start.
* @param dependentService the UIService this activator is waiting.
*/
@Override
public void start(Object dependentService)
{
if (logger.isDebugEnabled())
logger.debug("Update checker [STARTED]");
ConfigurationService cfg = getConfiguration();
if (OSUtils.IS_WINDOWS)
{
updateService = new UpdateServiceImpl();
bundleContext.registerService(
UpdateService.class.getName(),
updateService,
null);
// Register the "Check for Updates" menu item if
// the "Check for Updates" property isn't disabled.
if(!cfg.getBoolean(CHECK_FOR_UPDATES_MENU_DISABLED_PROP, false))
{
// Register the "Check for Updates" menu item.
Hashtable<String, String> toolsMenuFilter
= new Hashtable<String, String>();
toolsMenuFilter.put(
Container.CONTAINER_ID,
Container.CONTAINER_HELP_MENU.getID());
bundleContext.registerService(
PluginComponentFactory.class.getName(),
new PluginComponentFactory(Container.CONTAINER_HELP_MENU)
{
@Override
protected PluginComponent getPluginInstance()
{
return new CheckForUpdatesMenuItemComponent(
getContainer(), this);
}
},
toolsMenuFilter);
}
// Check for software update upon startup if enabled.
if(cfg.getBoolean(UPDATE_ENABLED, true))
updateService.checkForUpdates(false);
}
if (cfg.getBoolean(CHECK_FOR_UPDATES_DAILY_ENABLED_PROP,
false))
{
logger.info("Scheduled update checking enabled");
// Schedule a "check for updates" task that will run once a day
int hoursToWait = calcHoursToWait();
Runnable updateRunnable = new Runnable()
{
public void run()
{
logger.debug("Performing scheduled update check");
getUpdateService().checkForUpdates(false);
}
};
mUpdateExecutor = Executors.newSingleThreadScheduledExecutor();
mUpdateExecutor.scheduleAtFixedRate(updateRunnable,
hoursToWait,
24*60*60,
TimeUnit.SECONDS);
}
if (logger.isDebugEnabled())
logger.debug("Update checker [REGISTERED]");
}
/**
* This activator depends on UIService.
* @return the class name of uiService.
*/
@Override
public Class<?> getDependentServiceClass()
{
return UIService.class;
}
/**
* Setting context to the activator, as soon as we have one.
*
* @param context the context to set.
*/
@Override
public void setBundleContext(BundleContext context)
{
bundleContext = context;
}
/**
* Calculate the number of hour to wait until the first scheduled update
* check. This will only be called if daily checking for config updates
* is enabled
*
* @return The number of hours to wait
*/
private int calcHoursToWait()
{
// The hours to wait is the number of hours until midnight tonight (24
// minus the current hour) plus the hour that the config says updates
// should be
return 24 - Calendar.getInstance().get(Calendar.HOUR_OF_DAY) +
configuration.getInt(CHECK_FOR_UPDATES_DAILY_TIME_PROP, 0);
}
/**
* Stop the bundle. Nothing to stop for now.
* @param bundleContext <tt>BundleContext</tt> provided by OSGi framework
* @throws Exception if something goes wrong during stop
*/
public void stop(BundleContext bundleContext) throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Update checker [STOPPED]");
if (mUpdateExecutor != null)
{
mUpdateExecutor.shutdown();
mUpdateExecutor = null;
}
}
/**
* Returns the update service instance.
*
* @return the update service instance
*/
static UpdateService getUpdateService()
{
return updateService;
}
}