/*
* Created on 27-Apr-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.update.sf.impl2;
/**
* @author parg
*
*/
import java.util.*;
import java.net.Proxy;
import java.net.URL;
import java.net.URLEncoder;
import java.io.IOException;
import java.io.InputStream;
import org.gudy.azureus2.platform.PlatformManager;
import org.gudy.azureus2.platform.PlatformManagerCapabilities;
import org.gudy.azureus2.platform.PlatformManagerFactory;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.PluginState;
import org.gudy.azureus2.plugins.utils.resourcedownloader.*;
import org.gudy.azureus2.pluginsimpl.update.sf.*;
import org.gudy.azureus2.pluginsimpl.local.PluginInitializer;
import org.gudy.azureus2.pluginsimpl.local.utils.resourcedownloader.*;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.SystemProperties;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.UrlUtils;
import org.gudy.azureus2.core3.logging.*;
import com.aelitis.azureus.core.proxy.AEProxyFactory;
import com.aelitis.azureus.core.proxy.AEProxyFactory.PluginProxy;
import com.aelitis.azureus.core.versioncheck.VersionCheckClient;
public class
SFPluginDetailsLoaderImpl
implements SFPluginDetailsLoader, ResourceDownloaderListener
{
private static final LogIDs LOGID = LogIDs.CORE;
private static final String site_prefix_default = Constants.SF_WEB_SITE;
private static String site_prefix;
static{
try{
Map data = VersionCheckClient.getSingleton().getVersionCheckInfo( VersionCheckClient.REASON_PLUGIN_UPDATE );
byte[] b_sp = (byte[])data.get("plugin_update_url");
if ( b_sp == null ){
site_prefix = site_prefix_default;
}else{
site_prefix = new String( b_sp );
}
}catch( Throwable e ){
site_prefix = site_prefix_default;
}
}
private static String base_url_params;
static{
base_url_params = "version=" + Constants.AZUREUS_VERSION + "&app=" + SystemProperties.getApplicationName();
try{
base_url_params += "&os=" + URLEncoder.encode(System.getProperty( "os.name"),"UTF-8" );
base_url_params += "&osv=" + URLEncoder.encode(System.getProperty( "os.version" ),"UTF-8" );
base_url_params += "&arch=" + URLEncoder.encode(System.getProperty( "os.arch"),"UTF-8" );
base_url_params += "&ui=" + URLEncoder.encode(COConfigurationManager.getStringParameter("ui"),"UTF-8" );
base_url_params += "&java=" + URLEncoder.encode(Constants.JAVA_VERSION,"UTF-8" );
if ( Constants.API_LEVEL > 0 ){
base_url_params += "&api_level=" + Constants.API_LEVEL;
}
try {
Class c = Class.forName( "org.eclipse.swt.SWT" );
String swt_platform = (String)c.getMethod( "getPlatform", new Class[]{} ).invoke( null, new Object[]{} );
base_url_params += "&swt_platform=" + swt_platform;
Integer swt_version = (Integer)c.getMethod( "getVersion", new Class[]{} ).invoke( null, new Object[]{} );
base_url_params += "&swt_version=" + swt_version;
}catch( Throwable e ){
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
private static String page_url = site_prefix + "update/pluginlist3.php?type=&" + base_url_params;
static{
try{
PlatformManager pm = PlatformManagerFactory.getPlatformManager();
if ( pm.hasCapability( PlatformManagerCapabilities.GetVersion )){
page_url += "&pmv=" + pm.getVersion();
}
}catch( Throwable e ){
}
}
private static SFPluginDetailsLoaderImpl singleton;
private static AEMonitor class_mon = new AEMonitor( "SFPluginDetailsLoader:class" );
private static final int RELOAD_MIN_TIME = 60*60*1000;
public static SFPluginDetailsLoader
getSingleton()
{
try{
class_mon.enter();
if ( singleton == null ){
singleton = new SFPluginDetailsLoaderImpl();
}
return( singleton );
}finally{
class_mon.exit();
}
}
protected boolean plugin_ids_loaded;
protected long plugin_ids_loaded_at;
protected List plugin_ids;
protected Map plugin_map;
protected List listeners = new ArrayList();
protected ResourceDownloaderFactory rd_factory = ResourceDownloaderFactoryImpl.getSingleton();
protected AEMonitor this_mon = new AEMonitor( "SFPluginDetailsLoader" );
protected
SFPluginDetailsLoaderImpl()
{
reset();
}
protected String
getRelativeURLBase()
{
return( site_prefix );
}
protected void
loadPluginList()
throws SFPluginDetailsException
{
try{
String page_url_to_use = addEPIDS( page_url );
URL original_url = new URL( page_url_to_use );
URL url = original_url;
Proxy proxy = null;
PluginProxy plugin_proxy = null;
boolean tried_proxy = false;
boolean ok = false;
try{
while( true ){
try{
ResourceDownloader dl = rd_factory.create( url, proxy );
if ( plugin_proxy != null ){
dl.setProperty( "URL_HOST", plugin_proxy.getURLHostRewrite());
}
dl = rd_factory.getRetryDownloader( dl, 5 );
dl.addListener( this );
Properties details = new Properties();
InputStream is = dl.download();
details.load( is );
is.close();
Iterator it = details.keySet().iterator();
while( it.hasNext()){
String plugin_id = (String)it.next();
String data = (String)details.get(plugin_id);
int pos = 0;
List bits = new ArrayList();
while( pos < data.length()){
int p1 = data.indexOf(';',pos);
if ( p1 == -1 ){
bits.add( data.substring(pos).trim());
break;
}else{
bits.add( data.substring(pos,p1).trim());
pos = p1+1;
}
}
if (bits.size() < 3) {
Logger.log(new LogEvent(LOGID, LogEvent.LT_ERROR,
"SF loadPluginList failed for plugin '" + plugin_id
+ "'. Details array is " + bits.size() + " (3 min)"));
} else {
String version = (String) bits.get(0);
String cvs_version = (String) bits.get(1);
String name = (String) bits.get(2);
String category = "";
if (bits.size() > 3) {
category = (String) bits.get(3);
}
plugin_ids.add(plugin_id);
plugin_map.put(plugin_id.toLowerCase(MessageText.LOCALE_ENGLISH), new SFPluginDetailsImpl(this,
plugin_id, version, cvs_version, name, category));
}
}
ok = true;
break;
}catch( Throwable e ){
if ( !tried_proxy ){
tried_proxy = true;
plugin_proxy = AEProxyFactory.getPluginProxy( "loading plugin details", url );
if ( plugin_proxy == null ){
throw( e );
}else{
url = plugin_proxy.getURL();
proxy = plugin_proxy.getProxy();
}
}else{
throw( e );
}
}
}
}finally{
if ( plugin_proxy != null ){
plugin_proxy.setOK( ok );
}
}
plugin_ids_loaded = true;
plugin_ids_loaded_at = SystemTime.getCurrentTime();
}catch( Throwable e ){
Debug.printStackTrace( e );
throw( new SFPluginDetailsException( "Plugin list load failed", e ));
}
}
private String
addEPIDS(
String str )
{
try{
String pids = "";
PluginInterface[] pis = PluginInitializer.getDefaultInterface().getPluginManager().getPluginInterfaces();
for ( PluginInterface pi: pis ){
PluginState ps = pi.getPluginState();
if ( !( ps.isBuiltIn() || ps.isDisabled())){
String version = pi.getPluginVersion();
if ( version != null && Constants.compareVersions( version, "0" ) > 0 ){
String pid = pi.getPluginID();
if ( pid != null && pid.length() > 0 ){
pids += pid + ":";
}
}
}
}
str += "&epids=" + UrlUtils.encode( pids );
}catch( Throwable e ){
Debug.out( e );
}
return( str );
}
protected void
loadPluginDetails(
SFPluginDetailsImpl details )
throws SFPluginDetailsException
{
try{
String page_url_to_use = site_prefix + "update/pluginlist3.php?plugin="
+ UrlUtils.encode(details.getId()) + "&" + base_url_params;
page_url_to_use = addEPIDS( page_url_to_use );
try{
PluginInterface defPI = PluginInitializer.getDefaultInterface();
PluginInterface pi = defPI == null ? null : defPI.getPluginManager().getPluginInterfaceByID( details.getId(), false );
if ( pi != null ){
String existing_version = pi.getPluginVersion();
if ( existing_version != null ){
page_url_to_use += "&ver_" + details.getId() + "=" + UrlUtils.encode( existing_version );
}
}
}catch( Throwable e ){
Debug.out( e );
}
URL original_url = new URL( page_url_to_use );
URL url = original_url;
Proxy proxy = null;
PluginProxy plugin_proxy = null;
boolean tried_proxy = false;
boolean ok = false;
try{
while( true ){
try{
ResourceDownloader p_dl = rd_factory.create( url, proxy );
if ( proxy != null ){
p_dl.setProperty( "URL_HOST", original_url.getHost());
}
p_dl = rd_factory.getRetryDownloader( p_dl, 5 );
p_dl.addListener( this );
InputStream is = p_dl.download();
try{
if ( !processPluginStream( details, is )){
throw( new SFPluginDetailsException( "Plugin details load fails for '" + details.getId() + "': data not found" ));
}
ok = true;
break;
}finally{
is.close();
}
}catch( Throwable e ){
if ( !tried_proxy ){
tried_proxy = true;
plugin_proxy = AEProxyFactory.getPluginProxy( "loading plugin details", url );
if ( plugin_proxy == null ){
throw( e );
}else{
url = plugin_proxy.getURL();
proxy = plugin_proxy.getProxy();
}
}else{
throw( e );
}
}
}
}finally{
if ( plugin_proxy != null ){
plugin_proxy.setOK( ok );
}
}
}catch( Throwable e ){
Debug.printStackTrace( e );
throw( new SFPluginDetailsException( "Plugin details load fails", e ));
}
}
protected boolean
processPluginStream(SFPluginDetailsImpl details, InputStream is) {
Properties properties = new Properties();
try {
properties.load(is);
String pid = details.getId();
String download_url = properties.getProperty(pid + ".dl_link", "");
download_url = download_url.length() == 0 ? "<unknown>" : site_prefix + download_url;
String author = properties.getProperty(pid + ".author", "");
String desc = properties.getProperty(pid + ".description", "");
String cvs_download_url = properties.getProperty(pid + ".dl_link_cvs", null);
cvs_download_url = (cvs_download_url==null||cvs_download_url.length() == 0 )? "<unknown>" : site_prefix + cvs_download_url;
String comment = properties.getProperty(pid + ".comment", "");
// I don't think this one is ever set (not even in the old html scraping code)
String info_url = properties.getProperty(pid + ".info_url", null);
details.setDetails(
download_url,
author,
cvs_download_url,
desc,
comment,
info_url);
return true;
} catch (IOException e) {
Debug.out(e);
}
return false;
}
public String[]
getPluginIDs()
throws SFPluginDetailsException
{
try{
this_mon.enter();
if ( !plugin_ids_loaded ){
loadPluginList();
}
String[] res = new String[plugin_ids.size()];
plugin_ids.toArray( res );
return( res );
}finally{
this_mon.exit();
}
}
public SFPluginDetails
getPluginDetails(
String name )
throws SFPluginDetailsException
{
try{
this_mon.enter();
// make sure details are loaded
getPluginIDs();
SFPluginDetails details = (SFPluginDetails)plugin_map.get(name.toLowerCase(MessageText.LOCALE_ENGLISH));
if ( details == null ){
throw( new SFPluginDetailsException( "Plugin '" + name + "' not found" ));
}
return( details );
}finally{
this_mon.exit();
}
}
public SFPluginDetails[]
getPluginDetails()
throws SFPluginDetailsException
{
String[] plugin_ids = getPluginIDs();
SFPluginDetails[] res = new SFPluginDetails[plugin_ids.length];
for (int i=0;i<plugin_ids.length;i++){
res[i] = getPluginDetails(plugin_ids[i]);
}
return( res );
}
public void
reportPercentComplete(
ResourceDownloader downloader,
int percentage )
{
}
public void
reportAmountComplete(
ResourceDownloader downloader,
long amount )
{
}
public void
reportActivity(
ResourceDownloader downloader,
String activity )
{
informListeners( activity );
}
public boolean
completed(
ResourceDownloader downloader,
InputStream data )
{
return( true );
}
public void
failed(
ResourceDownloader downloader,
ResourceDownloaderException e )
{
informListeners( "Error: " + e.getMessage());
}
protected void
informListeners(
String log )
{
for (int i=0;i<listeners.size();i++){
((SFPluginDetailsLoaderListener)listeners.get(i)).log( log );
}
}
public void
reset()
{
try{
this_mon.enter();
long now = SystemTime.getCurrentTime();
// handle backward time changes
if ( now < plugin_ids_loaded_at ){
plugin_ids_loaded_at = 0;
}
if ( now - plugin_ids_loaded_at > RELOAD_MIN_TIME ){
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID,
"SFPluginDetailsLoader: resetting values"));
plugin_ids_loaded = false;
plugin_ids = new ArrayList();
plugin_map = new HashMap();
}else{
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
"SFPluginDetailsLoader: not resetting, " + "cache still valid"));
}
}finally{
this_mon.exit();
}
}
public void
addListener(
SFPluginDetailsLoaderListener l )
{
listeners.add( l );
}
public void
removeListener(
SFPluginDetailsLoaderListener l )
{
listeners.remove(l);
}
}