// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.gui.PleaseWaitRunnable;
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
import org.openstreetmap.josm.io.OsmTransferException;
import org.xml.sax.SAXException;
/**
* This is an asynchronous task for reading plugin information from the files
* in the local plugin repositories.
*
* It scans the files in the local plugins repository (see {@see Preferences#getPluginsDirectory()}
* and extracts plugin information from three kind of files:
*
* - .jar-files, assuming that they represent plugin jars
* - .jar.new-files, assuming that these are downloaded but not yet installed plugins
* - cached lists of available plugins, downloaded for instance from
* http://josm.openstreetmap.de/plugins
*
*
*/
public class ReadLocalPluginInformationTask extends PleaseWaitRunnable {
private Map availablePlugins;
private boolean canceled;
public ReadLocalPluginInformationTask() {
super(tr("Reading local plugin information.."), false);
availablePlugins = new HashMap();
}
public ReadLocalPluginInformationTask(ProgressMonitor monitor) {
super(tr("Reading local plugin information.."),monitor, false);
availablePlugins = new HashMap();
}
@Override
protected void cancel() {
canceled = true;
}
@Override
protected void finish() {}
protected void processJarFile(File f, String pluginName) throws PluginException{
PluginInformation info = new PluginInformation(
f,
pluginName
);
if (!availablePlugins.containsKey(info.getName())) {
availablePlugins.put(info.getName(), info);
} else {
availablePlugins.get(info.getName()).localversion = info.version;
}
}
protected void scanSiteCacheFiles(ProgressMonitor monitor, File pluginsDirectory) {
File[] siteCacheFiles = pluginsDirectory.listFiles(
new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.matches("^([0-9]+-)?site.*\\.txt$");
}
}
);
if (siteCacheFiles == null || siteCacheFiles.length == 0)
return;
monitor.subTask(tr("Processing plugin site cache files..."));
monitor.setTicksCount(siteCacheFiles.length);
for (File f: siteCacheFiles) {
String fname = f.getName();
monitor.setCustomText(tr("Processing file ''{0}''", fname));
try {
processLocalPluginInformationFile(f);
} catch(PluginListParseException e) {
System.err.println(tr("Warning: Failed to scan file ''{0}'' for plugin information. Skipping.", fname));
e.printStackTrace();
}
monitor.worked(1);
}
}
protected void scanPluginFiles(ProgressMonitor monitor, File pluginsDirectory) {
File[] pluginFiles = pluginsDirectory.listFiles(
new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".jar") || name.endsWith(".jar.new");
}
}
);
if (pluginFiles == null || pluginFiles.length == 0)
return;
monitor.subTask(tr("Processing plugin files..."));
monitor.setTicksCount(pluginFiles.length);
for (File f: pluginFiles) {
String fname = f.getName();
monitor.setCustomText(tr("Processing file ''{0}''", fname));
try {
if (fname.endsWith(".jar")) {
String pluginName = fname.substring(0, fname.length() - 4);
processJarFile(f, pluginName);
} else if (fname.endsWith(".jar.new")) {
String pluginName = fname.substring(0, fname.length() - 8);
processJarFile(f, pluginName);
}
} catch(PluginException e){
System.err.println(tr("Warning: Failed to scan file ''{0}'' for plugin information. Skipping.", fname));
e.printStackTrace();
}
monitor.worked(1);
}
}
protected void scanLocalPluginRepository(ProgressMonitor monitor, File pluginsDirectory) {
if (pluginsDirectory == null) return;
try {
monitor.beginTask("");
scanSiteCacheFiles(monitor, pluginsDirectory);
scanPluginFiles(monitor, pluginsDirectory);
} finally {
monitor.setCustomText("");
monitor.finishTask();
}
}
protected void processLocalPluginInformationFile(File file) throws PluginListParseException{
FileInputStream fin = null;
try {
fin = new FileInputStream(file);
List pis = new PluginListParser().parse(fin);
for (PluginInformation pi : pis) {
// we always keep plugin information from a plugin site because it
// includes information not available in the plugin jars Manifest, i.e.
// the download link or localized descriptions
//
availablePlugins.put(pi.name, pi);
}
} catch(IOException e) {
throw new PluginListParseException(e);
} finally {
if (fin != null) {
try {
fin.close();
} catch(IOException e){ /* ignore */}
}
}
}
protected void analyseInProcessPlugins() {
for (PluginProxy proxy : PluginHandler.pluginList) {
if (canceled)return;
if (!availablePlugins.containsKey(proxy.info.name)) {
availablePlugins.put(proxy.info.name, proxy.info);
} else {
availablePlugins.get(proxy.info.name).localversion = proxy.info.version;
}
}
}
protected void filterOldPlugins() {
for (String p : PluginHandler.DEPRECATED_PLUGINS) {
if (canceled)return;
if (availablePlugins.containsKey(p)) {
availablePlugins.remove(p);
}
}
}
@Override
protected void realRun() throws SAXException, IOException, OsmTransferException {
Collection pluginLocations = PluginInformation.getPluginLocations();
getProgressMonitor().setTicksCount(pluginLocations.size() + 2);
if (canceled)return;
scanLocalPluginRepository(
getProgressMonitor().createSubTaskMonitor(1, false),
Main.pref.getPluginsDirectory()
);
getProgressMonitor().worked(1);
if (canceled)return;
analyseInProcessPlugins();
getProgressMonitor().worked(1);
if (canceled)return;
filterOldPlugins();
getProgressMonitor().worked(1);
}
/**
* Replies information about available plugins detected by this task.
*
* @return information about available plugins detected by this task.
*/
public List getAvailablePlugins() {
return new ArrayList(availablePlugins.values());
}
/**
* Replies true if the task was cancelled by the user
*
* @return true if the task was cancelled by the user
*/
public boolean isCanceled() {
return canceled;
}
}