/*
* Created on 12-May-2004
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.pluginsimpl.local.update;
/**
* @author parg
*
*/
import java.util.*;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.plugins.update.*;
import org.gudy.azureus2.plugins.utils.resourcedownloader.*;
public class
UpdateCheckInstanceImpl
implements UpdateCheckInstance
{
private static final LogIDs LOGID = LogIDs.CORE;
private static UpdateCheckInstanceImpl active_checker;
private List<UpdateCheckInstanceListener> listeners = new ArrayList<UpdateCheckInstanceListener>();
private List<UpdateImpl> updates = new ArrayList<UpdateImpl>();
private List<UpdateManagerDecisionListener> decision_listeners = new ArrayList<UpdateManagerDecisionListener>();
private AESemaphore sem = new AESemaphore("UpdateCheckInstance");
private UpdateManager manager;
private int check_type;
private String name;
private UpdatableComponentImpl[] components;
private UpdateCheckerImpl[] checkers;
private boolean completed;
private boolean cancelled;
private boolean automatic = true;
private boolean low_noise = false;
protected AEMonitor this_mon = new AEMonitor( "UpdateCheckInstance" );
private Map<Integer,Object> properties = new HashMap<Integer, Object>();
{
properties.put( PT_UI_STYLE, PT_UI_STYLE_DEFAULT );
}
protected
UpdateCheckInstanceImpl(
UpdateManager _manager,
int _check_type,
String _name,
UpdatableComponentImpl[] _components )
{
manager = _manager;
check_type = _check_type;
name = _name;
components = _components;
checkers = new UpdateCheckerImpl[components.length];
for (int i=0;i<components.length;i++){
UpdatableComponentImpl comp = components[i];
checkers[i] = new UpdateCheckerImpl( this, comp, sem );
}
}
public int
getType()
{
return( check_type );
}
public String
getName()
{
return( name );
}
public void
addUpdatableComponent(
UpdatableComponent component,
boolean mandatory )
{
// add new component
UpdatableComponentImpl comp = new UpdatableComponentImpl( component, mandatory );
UpdatableComponentImpl[] new_comps = new UpdatableComponentImpl[components.length+1];
System.arraycopy( components, 0, new_comps, 0, components.length );
new_comps[components.length] = comp;
components = new_comps;
// add a new checker
UpdateCheckerImpl checker = new UpdateCheckerImpl( this, comp, sem );
UpdateCheckerImpl[] new_checkers = new UpdateCheckerImpl[checkers.length+1];
System.arraycopy( checkers, 0, new_checkers, 0, checkers.length );
new_checkers[checkers.length] = checker;
checkers = new_checkers;
}
public void
setAutomatic(
boolean a )
{
automatic = a;
}
public boolean
isAutomatic()
{
return( automatic );
}
public void
setLowNoise(
boolean a )
{
low_noise = a;
}
public boolean
isLowNoise()
{
return( low_noise );
}
public Object
getProperty(
int property_name )
{
return( properties.get( property_name ));
}
public void
setProperty(
int property_name,
Object value )
{
properties.put( property_name, value );
}
public void
start()
{
// only run one at a time - easiest approach is just to use a couple of threads
// to backoff + check for completion
boolean run_now;
synchronized( UpdateCheckInstanceImpl.class ){
if ( active_checker == null ){
// System.out.println( "UCI: starting " + getName());
active_checker = this;
run_now = true;
new AEThread2( "UCI:clearer" )
{
public void
run()
{
// wait until the process completes then clear down the 'active' one
while( true ){
try{
Thread.sleep(1000);
}catch( Throwable e ){
}
if ( isCompleteOrCancelled()){
boolean done = true;
if ( completed ){
Update[] updates = getUpdates();
for ( Update update: updates ){
if ( !( update.isCancelled() || update.isComplete())){
done = false;
break;
}
}
}
if ( done ){
try{
Thread.sleep( 5000 );
}catch( Throwable e ){
}
// System.out.println( "UCI: done " + getName());
synchronized( UpdateCheckInstanceImpl.class ){
active_checker = null;
}
break;
}
}
}
}
}.start();
}else{
run_now = false;
// System.out.println( "UCI: waiting " + getName());
new AEThread2( "UCI:waiter" )
{
public void
run()
{
// wait until inactive then re-attempt
while( true ){
try{
Thread.sleep(1000);
}catch( Throwable e ){
}
boolean retry = false;
synchronized( UpdateCheckInstanceImpl.class ){
if ( active_checker == null ){
retry = true;
}
}
if ( retry ){
UpdateCheckInstanceImpl.this.start();
break;
}
}
}
}.start();
}
}
if ( run_now ){
startSupport();
}
}
private void
startSupport()
{
for (int i=0;i<components.length;i++){
final UpdateCheckerImpl checker = checkers[i];
new AEThread2( "UpdatableComponent Checker:" + i, true )
{
public void
run()
{
try{
checker.getComponent().checkForUpdate( checker );
}catch( Throwable e ){
checker.reportProgress( "Update check failed: " + Debug.getNestedExceptionMessage( e ));
e.printStackTrace();
checker.failed();
}
}
}.start();
}
new AEThread2( "UpdatableComponent Completion Waiter", true )
{
public void
run()
{
for (int i=0;i<components.length;i++){
sem.reserve();
}
try{
boolean mandatory_failed = false;
for (int i=0;i<checkers.length;i++){
if ( components[i].isMandatory() && checkers[i].getFailed()){
mandatory_failed = true;
break;
}
}
List<UpdateImpl> target_updates = new ArrayList<UpdateImpl>();
// if any mandatory checks failed then we can't do any more
if ( mandatory_failed ){
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, LogEvent.LT_ERROR,
"Dropping all updates as a mandatory update check failed"));
}else{
// If there are any manadatory updates then we just go ahead with them and drop the rest
boolean mandatory_only = false;
for (int i=0;i<updates.size();i++){
UpdateImpl update = (UpdateImpl)updates.get(i);
if ( update.isMandatory()){
mandatory_only = true;
break;
}
}
for (int i=0;i<updates.size();i++){
UpdateImpl update = (UpdateImpl)updates.get(i);
if ( update.isMandatory() || !mandatory_only ){
target_updates.add( update );
}else{
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, LogEvent.LT_ERROR,
"Dropping update '" + update.getName()
+ "' as non-mandatory and "
+ "mandatory updates found"));
}
}
}
// maintain order here as we apply updates in the order we
// were requested to
Collections.sort(
target_updates,
new Comparator<UpdateImpl>()
{
public int
compare(
UpdateImpl o1, UpdateImpl o2)
{
int i1 = getIndex( o1 );
int i2 = getIndex( o2 );
return( i1 - i2 );
}
private int
getIndex(
UpdateImpl update )
{
UpdatableComponentImpl component = update.getComponent();
for (int i=0;i<components.length;i++){
if ( components[i] == component ){
return( i );
}
}
Debug.out( "Missing component!" );
return( 0 );
}
});
updates = target_updates;
}finally{
try{
this_mon.enter();
if ( cancelled ){
return;
}
completed = true;
}finally{
this_mon.exit();
}
}
for (int i=0;i<listeners.size();i++){
try{
((UpdateCheckInstanceListener)listeners.get(i)).complete( UpdateCheckInstanceImpl.this );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
}.start();
}
protected UpdateImpl
addUpdate(
UpdatableComponentImpl comp,
String update_name,
String[] desc,
String new_version,
ResourceDownloader[] downloaders,
int restart_required )
{
try{
this_mon.enter();
UpdateImpl update =
new UpdateImpl( this, comp, update_name, desc, new_version,
downloaders, comp.isMandatory(), restart_required );
updates.add( update );
if ( cancelled ){
update.cancel();
}
return( update );
}finally{
this_mon.exit();
}
}
public Update[]
getUpdates()
{
try{
this_mon.enter();
Update[] res = new Update[updates.size()];
updates.toArray( res );
return( res );
}finally{
this_mon.exit();
}
}
public UpdateChecker[]
getCheckers()
{
return( checkers );
}
public UpdateInstaller
createInstaller()
throws UpdateException
{
return( manager.createInstaller());
}
public boolean
isCompleteOrCancelled()
{
try{
this_mon.enter();
return( completed || cancelled );
}finally{
this_mon.exit();
}
}
public void
cancel()
{
boolean just_do_updates = false;
try{
this_mon.enter();
if ( completed ){
just_do_updates = true;
}
cancelled = true;
}finally{
this_mon.exit();
}
for (int i=0;i<updates.size();i++){
((UpdateImpl)updates.get(i)).cancel();
}
if ( !just_do_updates ){
for (int i=0;i<checkers.length;i++){
if ( checkers[i] != null ){
checkers[i].cancel();
}
}
for (int i=0;i<listeners.size();i++){
try{
((UpdateCheckInstanceListener)listeners.get(i)).cancelled( this );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
}
public boolean
isCancelled()
{
return( cancelled );
}
public UpdateManager
getManager()
{
return( manager );
}
protected Object
getDecision(
Update update,
int decision_type,
String decision_name,
String decision_description,
Object decision_data )
{
for (int i=0;i<decision_listeners.size();i++){
Object res =
((UpdateManagerDecisionListener)decision_listeners.get(i)).decide(
update, decision_type, decision_name, decision_description, decision_data );
if ( res != null ){
return( res );
}
}
return( null );
}
public void
addDecisionListener(
UpdateManagerDecisionListener l )
{
decision_listeners.add(l);
}
public void
removeDecisionListener(
UpdateManagerDecisionListener l )
{
decision_listeners.remove(l);
}
public void
addListener(
UpdateCheckInstanceListener l )
{
listeners.add( l );
if ( completed ){
l.complete( this );
}else if ( cancelled ){
l.cancelled( this );
}
}
public void
removeListener(
UpdateCheckInstanceListener l )
{
listeners.remove(l);
}
}