/* * Created on 28-Nov-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.installer; /** * @author parg * */ import java.io.File; import java.io.InputStream; import java.util.*; import org.gudy.azureus2.core3.logging.*; import org.gudy.azureus2.core3.util.Constants; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.FileUtil; import org.gudy.azureus2.plugins.*; import org.gudy.azureus2.plugins.installer.*; import org.gudy.azureus2.plugins.update.*; import org.gudy.azureus2.plugins.utils.resourcedownloader.ResourceDownloader; import org.gudy.azureus2.plugins.utils.resourcedownloader.ResourceDownloaderAdapter; import org.gudy.azureus2.plugins.utils.resourcedownloader.ResourceDownloaderException; import org.gudy.azureus2.pluginsimpl.local.FailedPlugin; import org.gudy.azureus2.pluginsimpl.update.sf.*; import org.gudy.azureus2.pluginsimpl.update.PluginUpdatePlugin; public class PluginInstallerImpl implements PluginInstaller { protected static PluginInstallerImpl singleton; public static PluginInstallerImpl getSingleton( PluginManager _manager ) { if ( singleton == null ){ singleton = new PluginInstallerImpl( _manager ); } return( singleton ); } private PluginManager manager; private List listeners = new ArrayList(); protected PluginInstallerImpl( PluginManager _manager ) { manager = _manager; } protected PluginManager getPluginManager() { return( manager ); } public StandardPlugin[] getStandardPlugins() throws PluginException { try{ SFPluginDetailsLoader loader = SFPluginDetailsLoaderFactory.getSingleton(); SFPluginDetails[] details = loader.getPluginDetails(); List res = new ArrayList(); for (int i=0;i<details.length;i++){ SFPluginDetails detail = details[i]; String name = detail.getId(); String version = ""; if ( Constants.isCVSVersion()){ version = detail.getCVSVersion(); } if ( version == null || version.length() == 0 || !Character.isDigit(version.charAt(0))){ version = detail.getVersion(); }else{ // if cvs version and non-cvs version are the same then show the // non-cvs version String non_cvs_version = detail.getVersion(); if ( version.equals( non_cvs_version + "_CVS" )){ version = non_cvs_version; } } if ( name.startsWith( "azplatform" ) || name.equals( "azupdater" )){ // skip built in ones we don't want to let user install directly // not the cleanest of fixes, but it'll do for the moment }else if ( version == null || version.length() == 0 || !Character.isDigit(version.charAt(0))){ // dodgy version }else if ( detail.getCategory().equalsIgnoreCase("hidden")){ // not public }else{ res.add( new StandardPluginImpl( this, details[i], version )); } } StandardPlugin[] res_a = new StandardPlugin[res.size()]; res.toArray( res_a ); return( res_a ); }catch( SFPluginDetailsException e ){ throw( new PluginException("Failed to load standard plugin details", e )); } } public FilePluginInstaller installFromFile( File file ) throws PluginException { return( new FilePluginInstallerImpl(this,file)); } public void install( InstallablePlugin installable_plugin, boolean shared ) throws PluginException { install( new InstallablePlugin[]{installable_plugin}, shared ); } public void install( InstallablePlugin[] plugins, boolean shared ) throws PluginException { PluginUpdatePlugin pup = (PluginUpdatePlugin)manager.getPluginInterfaceByClass( PluginUpdatePlugin.class ).getPlugin(); UpdateManager uman = manager.getDefaultPluginInterface().getUpdateManager(); UpdateCheckInstance inst = uman.createEmptyUpdateCheckInstance( UpdateCheckInstance.UCI_INSTALL, "update.instance.install" ); try{ for (int i=0;i<plugins.length;i++){ InstallablePlugin plugin = plugins[i]; String plugin_id = plugin.getId(); PluginInterface existing_plugin_interface = manager.getPluginInterfaceByID( plugin_id ); Plugin existing_plugin = null; if ( existing_plugin_interface != null ){ existing_plugin = existing_plugin_interface.getPlugin(); // try to check that the new version is higher than the old one! String old_version = existing_plugin_interface.getPluginVersion(); if ( old_version != null ){ int res = Constants.compareVersions( plugin.getVersion(), old_version ); if ( res < 0 ){ throw( new PluginException( "A higher version (" + old_version + ") of Plugin '" + plugin_id + "' is already installed" )); }else if ( res == 0 ){ throw( new PluginException( "Version (" + old_version + ") of Plugin '" + plugin_id + "' is already installed" )); } } } String target_dir; if ( shared ){ target_dir = FileUtil.getApplicationFile( "plugins" ).toString(); }else{ target_dir = FileUtil.getUserFile( "plugins" ).toString(); } target_dir += File.separator + plugin_id; // this may fail on Vista but it doesn't matter as we recover this later // on. So *don't* check for success here new File( target_dir ).mkdir(); if ( existing_plugin == null ){ // create a dummy plugin at version 0.0 to trigger the "upgrade" to the new // installed version final FailedPlugin dummy_plugin = new FailedPlugin( plugin_id, target_dir ); PluginManager.registerPlugin( dummy_plugin, plugin_id ); PluginInterface dummy_plugin_interface = manager.getPluginInterfaceByID( plugin_id ); ((InstallablePluginImpl)plugin).addUpdate( inst, pup, dummy_plugin, dummy_plugin_interface ); inst.addListener( new UpdateCheckInstanceListener() { public void cancelled( UpdateCheckInstance instance ) { dummy_plugin.requestUnload(); } public void complete( UpdateCheckInstance instance ) { dummy_plugin.requestUnload(); } }); }else{ ((InstallablePluginImpl)plugin).addUpdate( inst, pup, existing_plugin, existing_plugin_interface ); } } inst.start(); }catch( Throwable e ){ inst.cancel(); if ( e instanceof PluginException ){ throw((PluginException)e); }else{ throw( new PluginException( "Failed to create installer", e )); } } } public void uninstall( InstallablePlugin standard_plugin ) throws PluginException { PluginInterface pi = standard_plugin.getAlreadyInstalledPlugin(); if ( pi == null ){ throw( new PluginException(" Plugin '" + standard_plugin.getId() + "' is not installed")); } pi.uninstall(); } public void uninstall( final PluginInterface pi ) throws PluginException { uninstall( new PluginInterface[]{ pi }); } public void uninstall( final PluginInterface[] pis ) throws PluginException { for (int i=0;i<pis.length;i++){ PluginInterface pi = pis[i]; if ( pi.isMandatory()){ throw( new PluginException( "Plugin '" + pi.getPluginID() + "' is mandatory, can't uninstall" )); } if ( pi.isBuiltIn()){ throw( new PluginException( "Plugin '" + pi.getPluginID() + "' is built-in, can't uninstall" )); } String plugin_dir = pi.getPluginDirectoryName(); if ( plugin_dir == null || !new File(plugin_dir).exists()){ throw( new PluginException( "Plugin '" + pi.getPluginID() + "' is not loaded from the file system, can't uninstall" )); } } try{ UpdateManager uman = manager.getDefaultPluginInterface().getUpdateManager(); UpdateCheckInstance inst = uman.createEmptyUpdateCheckInstance( UpdateCheckInstance.UCI_UNINSTALL, "update.instance.uninstall"); for (int i=0;i<pis.length;i++){ final PluginInterface pi = pis[i]; final String plugin_dir = pi.getPluginDirectoryName(); inst.addUpdatableComponent( new UpdatableComponent() { public String getName() { return( pi.getPluginName()); } public int getMaximumCheckTime() { return( 0 ); } public void checkForUpdate( final UpdateChecker checker ) { try{ ResourceDownloader rd = manager.getDefaultPluginInterface().getUtilities().getResourceDownloaderFactory().create( new File( plugin_dir )); rd.addListener( new ResourceDownloaderAdapter() { public boolean completed( ResourceDownloader downloader, InputStream data ) { try{ if ( pi.isUnloadable()){ pi.unload(); FileUtil.recursiveDelete( new File( plugin_dir )); } UpdateInstaller installer = checker.createInstaller(); installer.addRemoveAction( new File( plugin_dir ).getCanonicalPath()); }catch( Throwable e ){ Debug.printStackTrace(e); Logger.log(new LogAlert(LogAlert.REPEATABLE, "Plugin uninstall failed", e)); } // don't close the stream as we process it later return( true ); } public void failed( ResourceDownloader downloader, ResourceDownloaderException e ) { if ( !downloader.isCancelled()){ Logger.log(new LogAlert(LogAlert.REPEATABLE, "Plugin uninstall failed", e)); } } }); // the plugin may have > 1 plugin interfaces, make the name up appropriately String update_name = ""; PluginInterface[] ifs = manager.getPluginInterfaces(); Arrays.sort( ifs, new Comparator() { public int compare( Object o1, Object o2) { return(((PluginInterface)o1).getPluginName().compareTo(((PluginInterface)o2).getPluginName())); } }); for (int i=0;i<ifs.length;i++){ if ( ifs[i].getPluginID().equals(pi.getPluginID())){ update_name += (update_name.length()==0?"":",") + ifs[i].getPluginName(); } } checker.addUpdate( update_name, new String[]{ "Uninstall: " + plugin_dir}, pi.getPluginVersion(), rd, pi.isUnloadable()?Update.RESTART_REQUIRED_NO:Update.RESTART_REQUIRED_YES ); }finally{ checker.completed(); } } }, false ); } inst.start(); }catch( Throwable e ){ Debug.printStackTrace(e); } } protected PluginInterface getAlreadyInstalledPlugin( String id ) { return( getPluginManager().getPluginInterfaceByID(id)); } public void requestInstall( String reason, InstallablePlugin plugin ) throws PluginException { for (int i=0;i<listeners.size();i++){ if (((PluginInstallerListener)listeners.get(i)).installRequest( reason, plugin )){ return; } } throw( new PluginException( "No listeners registered to perform installation of '" + plugin.getName() +" (" + reason + ")" )); } public void addListener( PluginInstallerListener l ) { listeners.add( l ); } public void removeListener( PluginInstallerListener l ) { listeners.remove( l ); } }