/*
* @(#)JasenAutoUpdateManager.java 5/01/2005
*
* Copyright (c) 2005 jASEN.org
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
*
* 3. The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. Any modification or additions to the software must be contributed back
* to the project.
*
* 5. Any investigation or reverse engineering of source code or binary to
* enable emails to bypass the filters, and hence inflict spam and or viruses
* onto users who use or do not use jASEN could subject the perpetrator to
* criminal and or civil liability.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JASEN.ORG,
* OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.jasen.update;
import org.apache.log4j.Logger;
import org.jasen.JasenScanner;
import org.jasen.error.JasenException;
import org.jasen.interfaces.JasenErrorHandler;
import org.jasen.io.StreamReaderListener;
import org.jasen.util.ThreadUtils;
/**
* <p>
* The auto update manager is responsible for starting, stoping and scheduling the AutoUpdate thread.
* </p>
* <p>
* All access to the auto update system should be via this class. DO NOT access any other update class directly
* </p>
* @author Jason Polites
*/
public final class JasenAutoUpdateManager implements StreamReaderListener {
static final Logger logger = Logger.getLogger(JasenAutoUpdateManager.class);
private static JasenAutoUpdateManager instance;
private static final Object lock = new Object();
private JasenAutoUpdater updater;
private JasenAutoUpdateReaper reaper;
private JasenAutoUpdateNotifier notifier;
private JasenAutoUpdateConfiguration configuration;
private boolean initialized = false;
private volatile boolean updating = false;
private JasenErrorHandler errorHandler;
private boolean destroyed;
/**
*
*/
private JasenAutoUpdateManager() {
super();
}
public static final JasenAutoUpdateManager getInstance() {
if(instance == null) {
synchronized(lock) {
if(instance == null) {
instance = new JasenAutoUpdateManager();
}
lock.notifyAll();
}
}
return instance;
}
void assertInitialised() throws JasenException {
if(!initialized) {
throw new JasenException("Cannot perform requested operation on uninitialized AutoUpdate manager. Please ensure the auto update engine is enabled");
}
}
/**
* Initialises the manager with the given configuration object
* @param configuration
* @throws JasenException
*/
public synchronized void init(JasenAutoUpdateConfiguration configuration) throws JasenException {
logger.debug("Initialising auto update manager");
if(!initialized) {
this.configuration = configuration;
errorHandler = configuration.getErrorHandler();
// Create the update thread
updater = new JasenAutoUpdater(this, "JasenAutoUpdater");
// Create the reaper
reaper = new JasenAutoUpdateReaper(updater, this, "JasenAutoUpdateReaper");
// Create the notifier
notifier = new JasenAutoUpdateNotifier(this, "JasenAutoUpdateNotifier");
// Start the updater
logger.debug("Starting auto updater");
updater.start();
// Start the reaper
logger.debug("Starting auto updater reaper");
reaper.start();
// Start the notifyier
logger.debug("Starting auto updater notifier");
notifier.start();
initialized = true;
destroyed = false;
}
}
public synchronized void destroy() {
if(!destroyed) {
logger.debug("Stopping the updater");
// Stop the updater...
logger.debug("Waiting for auto updater to finish");
// Wait for the updater to finish...
if(!ThreadUtils.forceFinish(updater, JasenAutoUpdateReaper.killTimeout)) {
logger.warn("Auto Updater did not finish within the given timeout of " + JasenAutoUpdateReaper.killTimeout + " milliseconds and will be interrupted");
}
// Stop the reaper...
if(!ThreadUtils.forceFinish(reaper, JasenAutoUpdateReaper.killTimeout)) {
logger.warn("Auto Updater Reaper did not finish within the given timeout of " + JasenAutoUpdateReaper.killTimeout + " milliseconds and will be interrupted");
}
// Stop the notifier...
if(!ThreadUtils.forceFinish(notifier, JasenAutoUpdateReaper.killTimeout)) {
logger.warn("Auto Updater Notifier did not finish within the given timeout of " + JasenAutoUpdateReaper.killTimeout + " milliseconds and will be interrupted");
}
destroyed = true;
initialized = false;
}
}
public JasenAutoUpdateConfiguration getConfiguration() {
return configuration;
}
public JasenErrorHandler getErrorHandler() {
return errorHandler;
}
public synchronized boolean isInitialized() {
return initialized;
}
public boolean isIdle() {
return updater.isIdle();
}
public boolean forceUpdate() throws JasenException {
assertInitialised();
return updater.forceUpdate();
}
/**
* Called by the updater to signal that an update has occurred
* @param report A report of the results of the update
*/
void notifyUpdateComplete(JasenAutoUpdateReport report) {
logger.debug("Received update complete notification, notifying scanner");
notifier.notifyUpdateComplete(report);
updating = false;
}
/**
* Called by the updater to signal that an update is required
*
*/
void notifyUpdateRequired(JasenAutoUpdateParcel parcel) {
updating = true;
if(JasenScanner.getInstance().isAlive()) {
JasenScanner.getInstance().notifyPendingUpdate(parcel);
}
}
public void notifyBytesRead(long bytes) {
if(JasenScanner.getInstance().isAlive()) {
JasenScanner.getInstance().notifyUpdateDownload(bytes);
}
}
/**
* Indicates whether the auto update thread has signaled an update task underway
* @return true if the auto updater is updating, false otherwise
*/
public boolean isUpdating() {
return updating;
}
}