Package com.aelitis.azureus.core.subs.impl

Source Code of com.aelitis.azureus.core.subs.impl.SubscriptionSchedulerImpl

/*
* Created on Aug 6, 2008
* Created by Paul Gardner
*
* Copyright 2008 Vuze, Inc.  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; version 2 of the License only.
*
* 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.
*/


package com.aelitis.azureus.core.subs.impl;

import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.torrent.TOTorrentFactory;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.AESemaphore;
import org.gudy.azureus2.core3.util.AEThread2;
import org.gudy.azureus2.core3.util.AsyncDispatcher;
import org.gudy.azureus2.core3.util.SimpleTimer;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TimerEvent;
import org.gudy.azureus2.core3.util.TimerEventPerformer;
import org.gudy.azureus2.core3.util.TorrentUtils;
import org.gudy.azureus2.core3.util.UrlUtils;
import org.gudy.azureus2.plugins.download.Download;
import org.gudy.azureus2.plugins.download.DownloadManager;
import org.gudy.azureus2.plugins.torrent.Torrent;
import org.gudy.azureus2.plugins.utils.DelayedTask;
import org.gudy.azureus2.plugins.utils.StaticUtilities;
import org.gudy.azureus2.plugins.utils.resourcedownloader.ResourceDownloader;
import org.gudy.azureus2.plugins.utils.resourcedownloader.ResourceDownloaderFactory;
import org.gudy.azureus2.pluginsimpl.local.PluginInitializer;
import org.gudy.azureus2.pluginsimpl.local.torrent.TorrentImpl;
import org.gudy.azureus2.pluginsimpl.local.utils.UtilitiesImpl;

import com.aelitis.azureus.core.subs.Subscription;
import com.aelitis.azureus.core.subs.SubscriptionDownloadListener;
import com.aelitis.azureus.core.subs.SubscriptionException;
import com.aelitis.azureus.core.subs.SubscriptionHistory;
import com.aelitis.azureus.core.subs.SubscriptionManagerListener;
import com.aelitis.azureus.core.subs.SubscriptionResult;
import com.aelitis.azureus.core.subs.SubscriptionScheduler;

import com.aelitis.azureus.core.cnetwork.ContentNetwork;
import com.aelitis.azureus.core.cnetwork.ContentNetworkManagerFactory;
import com.aelitis.azureus.core.metasearch.Engine;
import com.aelitis.azureus.core.metasearch.impl.web.WebEngine;
import com.aelitis.azureus.util.ConstantsVuze;
import com.aelitis.azureus.util.UrlFilter;

public class
SubscriptionSchedulerImpl
  implements SubscriptionScheduler, SubscriptionManagerListener
{
  private static final Object      SCHEDULER_NEXT_SCAN_KEY       = new Object();
  private static final Object      SCHEDULER_FAILED_SCAN_CONSEC_KEY   = new Object();
  private static final Object      SCHEDULER_FAILED_SCAN_TIME_KEY     = new Object();
 
  private static final int      FAIL_INIT_DELAY    = 10*60*1000;
  private static final int      FAIL_MAX_DELAY    = 8*60*60*1000;
 
  private SubscriptionManagerImpl    manager;
 
  private Map  active_subscription_downloaders = new HashMap();
  private boolean active_subs_download_is_auto;
 
  private Set  active_result_downloaders    = new HashSet();
 
  private AsyncDispatcher  result_downloader = new AsyncDispatcher();

  private boolean    schedulng_permitted;
 
  private TimerEvent  schedule_event;
  private boolean    schedule_in_progress;
  private long    last_schedule;
 
 
  protected
  SubscriptionSchedulerImpl(
    SubscriptionManagerImpl    _manager )
  {
    manager  = _manager;
   
    manager.addListener( this );
   
    DelayedTask delayed_task = UtilitiesImpl.addDelayedTask( "Subscriptions Scheduler",
      new Runnable()
      {
        public void
        run()
        {
          synchronized( SubscriptionSchedulerImpl.this ){
           
            schedulng_permitted  = true;
          }
         
          calculateSchedule();
        }
      });
   
    delayed_task.queue();
  }
 
  public void
  downloadAsync(
    Subscription   subs,
    boolean     is_auto )
 
    throws SubscriptionException
  {
    download(
      subs,
      is_auto,
      new SubscriptionDownloadListener()
      {
        public void
        complete(
          Subscription    subs )
        {
        }
       
        public void
        failed(
          Subscription      subs,
          SubscriptionException  error )
        {
          log( "Async download of " + subs.getName() + " failed", error );
        }
      });
  }
 
  public void
  download(
    final Subscription           subs,
    final boolean            is_auto,
    final SubscriptionDownloadListener   listener )
  {
    new AEThread2( "SS:download", true )
    {
      public void
      run()
      {
        try{
          download( subs, is_auto );
         
          listener.complete( subs );
         
        }catch( SubscriptionException e ){
         
          listener.failed( subs, e );
         
        }catch( Throwable e ){
         
          listener.failed( subs, new SubscriptionException( "Download failed", e ));
        }
      }
    }.start();
  }
 
  public void
  download(
    Subscription   subs,
    boolean      is_auto )
 
    throws SubscriptionException
  {
    SubscriptionDownloader downloader;
   
    AESemaphore  sem = null;
   
    synchronized( active_subscription_downloaders ){
     
      List  waiting = (List)active_subscription_downloaders.get( subs );
     
      if ( waiting != null ){
       
        sem = new AESemaphore( "SS:waiter" );
       
        waiting.add( sem );
       
        if ( !is_auto ){
         
          active_subs_download_is_auto = false;
        }
      }else{
             
        active_subscription_downloaders.put( subs, new ArrayList());
       
        active_subs_download_is_auto = is_auto;
      }
 
      downloader = new SubscriptionDownloader(manager, (SubscriptionImpl)subs );
    }
   
    try{
      if ( sem == null ){
     
        downloader.download();
       
      }else{
       
        sem.reserve();
      }
    }finally{
     
      boolean  was_auto;
     
      synchronized( active_subscription_downloaders ){

        List waiting = (List)active_subscription_downloaders.remove( subs );
       
        if ( waiting != null ){
         
          for (int i=0;i<waiting.size();i++){
           
            ((AESemaphore)waiting.get(i)).release();
          }
        }
       
        was_auto = active_subs_download_is_auto;
      }
     
      ((SubscriptionImpl)subs).fireDownloaded( was_auto );
    }
  }
 
  public void
  download(
    final Subscription      subs,
    final SubscriptionResult  result )
  {
    String download_link = result.getDownloadLink();
   
    if ( download_link == null ){
     
      log( subs.getName() + ": can't download " + result.getID() + " as no direct download link available" );
     
      return;
    }

    if ( UrlFilter.getInstance().isWhitelisted( download_link )){
     
      ContentNetwork cn = ContentNetworkManagerFactory.getSingleton().getContentNetworkForURL( download_link );
     
      if ( cn == null ){
       
        cn = ConstantsVuze.getDefaultContentNetwork();
      }
     
      download_link = cn.appendURLSuffix( download_link, false, true );
    }
   
    final String  key = subs.getID() + ":" + result.getID();
    final String  dl  = download_link;
   
    synchronized( active_result_downloaders ){

      if ( active_result_downloaders.contains( key )){
       
        return;
      }
   
      active_result_downloaders.add( key );
     
      result_downloader.dispatch(
        new AERunnable()
        {
          public void
          runSupport()
          {
            try{
              boolean  retry = true;
           
              boolean  use_ref      = subs.getHistory().getDownloadWithReferer();
             
              boolean tried_ref_switch = false;
             
              while( retry ){
               
                retry = false;
             
                try{
                  TorrentUtils.setTLSDescription( "Subscription: " + subs.getName());

                  URL url = new URL(dl);
                                   
                  ResourceDownloaderFactory rdf = StaticUtilities.getResourceDownloaderFactory();
                 
                  ResourceDownloader url_rd = rdf.create( url );
                     
                  String referer = use_ref?subs.getReferer():null;
                 
                  UrlUtils.setBrowserHeaders( url_rd, referer );
                 
                  Engine engine = subs.getEngine();
                 
                  if ( engine instanceof WebEngine ){
                   
                    WebEngine we = (WebEngine)engine;
                   
                    if ( we.isNeedsAuth()){
                     
                      String cookies = we.getCookies();
                     
                      if ( cookies != null && cookies.length() > 0 ){
                       
                        url_rd.setProperty( "URL_Cookie", cookies );
                      }
                    }
                  }
                 
                  ResourceDownloader mr_rd = rdf.getMetaRefreshDownloader( url_rd );
   
                  InputStream is = mr_rd.download();
   
                  Torrent torrent = new TorrentImpl( TOTorrentFactory.deserialiseFromBEncodedInputStream( is ));
                           
                  // PlatformTorrentUtils.setContentTitle(torrent, torr );
             
                  DownloadManager dm = PluginInitializer.getDefaultInterface().getDownloadManager();
                 
                  Download  download;
                 
                  boolean auto_start = manager.shouldAutoStart( torrent );
                 
                  if ( auto_start ){
                 
                    download = dm.addDownload( torrent );
                   
                  }else{
                 
                    download = dm.addDownloadStopped( torrent, null, null );
                  }
                 
                  log( subs.getName() + ": added download " + download.getName()+ ": auto-start=" + auto_start );

                  subs.addAssociation( torrent.getHash());
                 
                  result.setRead( true );
                                   
                  if ( tried_ref_switch ){
                   
                    subs.getHistory().setDownloadWithReferer( use_ref );
                  }
                }catch( Throwable e ){
                 
                  log( subs.getName() + ": Failed to download result " + dl, e );
                 
                  if ( e instanceof TOTorrentException && !tried_ref_switch ){
                   
                    use_ref       = !use_ref;
                   
                    tried_ref_switch  = true;
                   
                    retry        = true;
                   
                    log( subs.getName() + ": Retrying " + (use_ref?"with referer":"without referer" ));
                  }
                }finally{
                 
                  TorrentUtils.setTLSDescription( null );
                }
              }
            }finally{
             
              synchronized( active_result_downloaders ){

                active_result_downloaders.remove( key );
              }
             
              calculateSchedule();
            }
          }
        });
    }
  }
 
  protected void
  calculateSchedule()
  {
    Subscription[]  subs = manager.getSubscriptions( true );
   
    synchronized( this ){
     
      if ( !schedulng_permitted ){
       
        return;
      }
     
      if ( schedule_in_progress ){
       
        return;
      }
     
      long  next_ready_time = Long.MAX_VALUE;
     
      for (int i=0;i<subs.length;i++){
       
        Subscription sub = subs[i];
               
        SubscriptionHistory history = sub.getHistory();
       
        if ( !history.isEnabled()){
         
          continue;
        }
       
        long  next_scan = getNextScan( sub );
       
        sub.setUserData( SCHEDULER_NEXT_SCAN_KEY, new Long( next_scan ));
       
        if ( next_scan < next_ready_time ){
         
          next_ready_time = next_scan;
        }
      }
   
      long   old_when = 0;
     
      if ( schedule_event != null ){
       
        old_when = schedule_event.getWhen();
       
        schedule_event.cancel();
       
        schedule_event = null;
      }
     
      if ( next_ready_time < Long.MAX_VALUE ){
       
        long  now = SystemTime.getCurrentTime();
       
        if (   now < last_schedule ||
            now - last_schedule < 30*1000 ){
         
          if ( next_ready_time - now < 30*1000 ){
           
            next_ready_time = now + 30*1000;
          }
        }
           
        log( "Calculate : " +
            "old_time=" + new SimpleDateFormat().format(new Date(old_when)) +
            ", new_time=" + new SimpleDateFormat().format(new Date(next_ready_time)));
           
        schedule_event = SimpleTimer.addEvent(
          "SS:Scheduler",
          next_ready_time,
          new TimerEventPerformer()
          {
            public void
            perform(
              TimerEvent event )
            {
              synchronized( SubscriptionSchedulerImpl.this ){
               
                if ( schedule_in_progress ){
                 
                  return;
                }
               
                schedule_in_progress = true;
               
                last_schedule = SystemTime.getCurrentTime();
               
                schedule_event = null;
              }
             
              new AEThread2( "SS:Sched", true )
              {
                public void
                run()
                {
                  try{
                    schedule();

                  }finally{
                   
                    synchronized( SubscriptionSchedulerImpl.this ){
                     
                      schedule_in_progress = false;
                    }
                   
                    calculateSchedule();
                  }
                }
              }.start();           
            }
          });
      }
    }
  }
 
  protected void
  schedule()
  {
    Subscription[]  subs = manager.getSubscriptions( true );
   
    long now = SystemTime.getCurrentTime();
     
    for (int i=0;i<subs.length;i++){
     
      Subscription sub = subs[i];
           
      SubscriptionHistory history = sub.getHistory();
     
      if ( !history.isEnabled()){
       
        continue;
      }
     
      synchronized( this ){
       
        Long  scan_due = (Long)sub.getUserData( SCHEDULER_NEXT_SCAN_KEY );
       
        if ( scan_due == null ){
         
          continue;
        }
       
        long diff = now - scan_due.longValue();
       
        if ( diff < -10*1000 ){
       
          continue;
        }
       
        sub.setUserData( SCHEDULER_NEXT_SCAN_KEY, null );
      }
     
      long  last_scan = history.getLastScanTime();

      try{
         
        download( sub, true );
       
      }catch( Throwable e ){
       
      }finally{
       
        long  new_last_scan = history.getLastScanTime();

        if ( new_last_scan == last_scan ){
         
          scanFailed( sub );
         
        }else{
         
          scanSuccess( sub );
        }
      }
    }
  }
 
  protected long
  getNextScan(
    Subscription    sub )
  {
    SubscriptionHistory  history = sub.getHistory();
       
    Long fail_count = (Long)sub.getUserData( SCHEDULER_FAILED_SCAN_CONSEC_KEY );
   
    if ( fail_count != null ){
     
      long   fail_time = ((Long)sub.getUserData( SCHEDULER_FAILED_SCAN_TIME_KEY )).longValue();
     
      long  fails = fail_count.longValue();
     
      long  backoff = FAIL_INIT_DELAY;
     
      for (int i=1;i<fails;i++){
       
        backoff <<= 1;
       
        if ( backoff > FAIL_MAX_DELAY ){
         
          backoff = FAIL_MAX_DELAY;
         
          break;
        }
      }
     
      return( fail_time + backoff );
    }

    return( history.getNextScanTime() );
  }
 
  protected void
  scanSuccess(
    Subscription    sub )
  {
    sub.setUserData( SCHEDULER_FAILED_SCAN_CONSEC_KEY, null );
  }
 
  protected void
  scanFailed(
    Subscription    sub )
  {
    sub.setUserData( SCHEDULER_FAILED_SCAN_TIME_KEY, new Long( SystemTime.getCurrentTime()));
   
    Long fail_count = (Long)sub.getUserData( SCHEDULER_FAILED_SCAN_CONSEC_KEY );
   
    if ( fail_count == null ){
     
      fail_count = new Long(1);
     
    }else{
     
      fail_count = new Long(fail_count.longValue()+1);
    }
   
    sub.setUserData( SCHEDULER_FAILED_SCAN_CONSEC_KEY, fail_count );
  }
 
  protected void
  log(
    String    str )
  {
    manager.log( "Scheduler: " + str );
  }
 
  protected void
  log(
    String    str,
    Throwable   e )
  {
    manager.log( "Scheduler: " + str, e );
  }
 
  public void
  subscriptionAdded(
    Subscription    subscription )
  {
    calculateSchedule();
  }
 
  public void
  subscriptionChanged(
    Subscription    subscription )
  {
    calculateSchedule();
  }
 
  public void
  subscriptionSelected(
    Subscription subscription )
  {   
  }
 
  public void
  subscriptionRemoved(
    Subscription    subscription )
  {
    calculateSchedule();
  }
 
  public void
  associationsChanged(
    byte[]        association_hash )
  {
  }
}
TOP

Related Classes of com.aelitis.azureus.core.subs.impl.SubscriptionSchedulerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.