[3083] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
| 2 | package org.openstreetmap.josm.plugins;
|
---|
| 3 |
|
---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
| 5 |
|
---|
| 6 | import java.awt.Component;
|
---|
| 7 | import java.io.File;
|
---|
| 8 | import java.io.FileOutputStream;
|
---|
| 9 | import java.io.IOException;
|
---|
| 10 | import java.io.InputStream;
|
---|
| 11 | import java.io.OutputStream;
|
---|
| 12 | import java.net.HttpURLConnection;
|
---|
| 13 | import java.net.MalformedURLException;
|
---|
| 14 | import java.net.URL;
|
---|
| 15 | import java.util.Collection;
|
---|
| 16 | import java.util.LinkedList;
|
---|
| 17 |
|
---|
| 18 | import org.openstreetmap.josm.Main;
|
---|
| 19 | import org.openstreetmap.josm.data.Version;
|
---|
| 20 | import org.openstreetmap.josm.gui.ExtendedDialog;
|
---|
| 21 | import org.openstreetmap.josm.gui.PleaseWaitRunnable;
|
---|
| 22 | import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
|
---|
| 23 | import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
---|
| 24 | import org.openstreetmap.josm.tools.CheckParameterUtil;
|
---|
[4087] | 25 | import org.openstreetmap.josm.tools.Utils;
|
---|
[3083] | 26 | import org.xml.sax.SAXException;
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | /**
|
---|
| 30 | * Asynchronous task for downloading a collection of plugins.
|
---|
[3530] | 31 | *
|
---|
[5266] | 32 | * When the task is finished {@link #getDownloadedPlugins()} replies the list of downloaded plugins
|
---|
| 33 | * and {@link #getFailedPlugins()} replies the list of failed plugins.
|
---|
[3530] | 34 | *
|
---|
[3083] | 35 | */
|
---|
| 36 | public class PluginDownloadTask extends PleaseWaitRunnable{
|
---|
[3090] | 37 | private final Collection<PluginInformation> toUpdate = new LinkedList<PluginInformation>();
|
---|
[3083] | 38 | private final Collection<PluginInformation> failed = new LinkedList<PluginInformation>();
|
---|
| 39 | private final Collection<PluginInformation> downloaded = new LinkedList<PluginInformation>();
|
---|
| 40 | private Exception lastException;
|
---|
| 41 | private boolean canceled;
|
---|
| 42 | private HttpURLConnection downloadConnection;
|
---|
| 43 |
|
---|
| 44 | /**
|
---|
| 45 | * Creates the download task
|
---|
[3530] | 46 | *
|
---|
[5266] | 47 | * @param parent the parent component relative to which the {@link PleaseWaitDialog} is displayed
|
---|
[3083] | 48 | * @param toUpdate a collection of plugin descriptions for plugins to update/download. Must not be null.
|
---|
[5266] | 49 | * @param title the title to display in the {@link PleaseWaitDialog}
|
---|
[3083] | 50 | * @throws IllegalArgumentException thrown if toUpdate is null
|
---|
| 51 | */
|
---|
| 52 | public PluginDownloadTask(Component parent, Collection<PluginInformation> toUpdate, String title) throws IllegalArgumentException{
|
---|
| 53 | super(parent, title == null ? "" : title, false /* don't ignore exceptions */);
|
---|
| 54 | CheckParameterUtil.ensureParameterNotNull(toUpdate, "toUpdate");
|
---|
[3090] | 55 | this.toUpdate.addAll(toUpdate);
|
---|
[3083] | 56 | }
|
---|
| 57 |
|
---|
| 58 | /**
|
---|
| 59 | * Creates the task
|
---|
[3530] | 60 | *
|
---|
[5266] | 61 | * @param monitor a progress monitor. Defaults to {@link NullProgressMonitor#INSTANCE} if null
|
---|
[3083] | 62 | * @param toUpdate a collection of plugin descriptions for plugins to update/download. Must not be null.
|
---|
[5266] | 63 | * @param title the title to display in the {@link PleaseWaitDialog}
|
---|
[3083] | 64 | * @throws IllegalArgumentException thrown if toUpdate is null
|
---|
| 65 | */
|
---|
| 66 | public PluginDownloadTask(ProgressMonitor monitor, Collection<PluginInformation> toUpdate, String title) {
|
---|
| 67 | super(title, monitor == null? NullProgressMonitor.INSTANCE: monitor, false /* don't ignore exceptions */);
|
---|
| 68 | CheckParameterUtil.ensureParameterNotNull(toUpdate, "toUpdate");
|
---|
[3090] | 69 | this.toUpdate.addAll(toUpdate);
|
---|
[3083] | 70 | }
|
---|
| 71 |
|
---|
[3090] | 72 | /**
|
---|
| 73 | * Sets the collection of plugins to update.
|
---|
[3530] | 74 | *
|
---|
[3090] | 75 | * @param toUpdate the collection of plugins to update. Must not be null.
|
---|
| 76 | * @throws IllegalArgumentException thrown if toUpdate is null
|
---|
| 77 | */
|
---|
| 78 | public void setPluginsToDownload(Collection<PluginInformation> toUpdate) throws IllegalArgumentException{
|
---|
| 79 | CheckParameterUtil.ensureParameterNotNull(toUpdate, "toUpdate");
|
---|
| 80 | this.toUpdate.clear();
|
---|
| 81 | this.toUpdate.addAll(toUpdate);
|
---|
| 82 | }
|
---|
| 83 |
|
---|
[3083] | 84 | @Override protected void cancel() {
|
---|
| 85 | this.canceled = true;
|
---|
| 86 | synchronized(this) {
|
---|
| 87 | if (downloadConnection != null) {
|
---|
| 88 | downloadConnection.disconnect();
|
---|
| 89 | }
|
---|
| 90 | }
|
---|
| 91 | }
|
---|
| 92 |
|
---|
| 93 | @Override protected void finish() {}
|
---|
| 94 |
|
---|
| 95 | protected void download(PluginInformation pi, File file) throws PluginDownloadException{
|
---|
| 96 | if (pi.mainversion > Version.getInstance().getVersion()) {
|
---|
| 97 | ExtendedDialog dialog = new ExtendedDialog(
|
---|
| 98 | Main.parent,
|
---|
| 99 | tr("Skip download"),
|
---|
| 100 | new String[] {
|
---|
| 101 | tr("Download Plugin"),
|
---|
| 102 | tr("Skip Download") }
|
---|
| 103 | );
|
---|
| 104 | dialog.setContent(tr("JOSM version {0} required for plugin {1}.", pi.mainversion, pi.name));
|
---|
| 105 | dialog.setButtonIcons(new String[] { "download.png", "cancel.png" });
|
---|
| 106 | dialog.showDialog();
|
---|
| 107 | int answer = dialog.getValue();
|
---|
| 108 | if (answer != 1)
|
---|
[3332] | 109 | throw new PluginDownloadException(tr("Download skipped"));
|
---|
[3083] | 110 | }
|
---|
| 111 | OutputStream out = null;
|
---|
| 112 | InputStream in = null;
|
---|
| 113 | try {
|
---|
| 114 | if (pi.downloadlink == null) {
|
---|
| 115 | String msg = tr("Warning: Cannot download plugin ''{0}''. Its download link is not known. Skipping download.", pi.name);
|
---|
| 116 | System.err.println(msg);
|
---|
| 117 | throw new PluginDownloadException(msg);
|
---|
| 118 | }
|
---|
| 119 | URL url = new URL(pi.downloadlink);
|
---|
| 120 | synchronized(this) {
|
---|
| 121 | downloadConnection = (HttpURLConnection)url.openConnection();
|
---|
| 122 | downloadConnection.setRequestProperty("Cache-Control", "no-cache");
|
---|
| 123 | downloadConnection.setRequestProperty("User-Agent",Version.getInstance().getAgentString());
|
---|
| 124 | downloadConnection.setRequestProperty("Host", url.getHost());
|
---|
| 125 | downloadConnection.connect();
|
---|
| 126 | }
|
---|
| 127 | in = downloadConnection.getInputStream();
|
---|
| 128 | out = new FileOutputStream(file);
|
---|
| 129 | byte[] buffer = new byte[8192];
|
---|
| 130 | for (int read = in.read(buffer); read != -1; read = in.read(buffer)) {
|
---|
| 131 | out.write(buffer, 0, read);
|
---|
| 132 | }
|
---|
| 133 | out.close();
|
---|
| 134 | in.close();
|
---|
| 135 | } catch(MalformedURLException e) {
|
---|
| 136 | String msg = tr("Warning: Cannot download plugin ''{0}''. Its download link ''{1}'' is not a valid URL. Skipping download.", pi.name, pi.downloadlink);
|
---|
| 137 | System.err.println(msg);
|
---|
| 138 | throw new PluginDownloadException(msg);
|
---|
| 139 | } catch (IOException e) {
|
---|
| 140 | if (canceled)
|
---|
| 141 | return;
|
---|
| 142 | throw new PluginDownloadException(e);
|
---|
| 143 | } finally {
|
---|
[4087] | 144 | Utils.close(in);
|
---|
[3083] | 145 | synchronized(this) {
|
---|
| 146 | downloadConnection = null;
|
---|
| 147 | }
|
---|
[4087] | 148 | Utils.close(out);
|
---|
[3083] | 149 | }
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | @Override protected void realRun() throws SAXException, IOException {
|
---|
| 153 | File pluginDir = Main.pref.getPluginsDirectory();
|
---|
| 154 | if (!pluginDir.exists()) {
|
---|
| 155 | if (!pluginDir.mkdirs()) {
|
---|
| 156 | lastException = new PluginDownloadException(tr("Failed to create plugin directory ''{0}''", pluginDir.toString()));
|
---|
| 157 | failed.addAll(toUpdate);
|
---|
| 158 | return;
|
---|
| 159 | }
|
---|
| 160 | }
|
---|
| 161 | getProgressMonitor().setTicksCount(toUpdate.size());
|
---|
| 162 | for (PluginInformation d : toUpdate) {
|
---|
| 163 | if (canceled) return;
|
---|
| 164 | progressMonitor.subTask(tr("Downloading Plugin {0}...", d.name));
|
---|
| 165 | progressMonitor.worked(1);
|
---|
| 166 | File pluginFile = new File(pluginDir, d.name + ".jar.new");
|
---|
| 167 | try {
|
---|
| 168 | download(d, pluginFile);
|
---|
| 169 | } catch(PluginDownloadException e) {
|
---|
| 170 | e.printStackTrace();
|
---|
| 171 | failed.add(d);
|
---|
| 172 | continue;
|
---|
| 173 | }
|
---|
| 174 | downloaded.add(d);
|
---|
| 175 | }
|
---|
| 176 | PluginHandler.installDownloadedPlugins(false);
|
---|
| 177 | }
|
---|
| 178 |
|
---|
| 179 | /**
|
---|
[4310] | 180 | * Replies true if the task was canceled by the user
|
---|
[3530] | 181 | *
|
---|
[3083] | 182 | * @return
|
---|
| 183 | */
|
---|
| 184 | public boolean isCanceled() {
|
---|
| 185 | return canceled;
|
---|
| 186 | }
|
---|
| 187 |
|
---|
| 188 | /**
|
---|
| 189 | * Replies the list of successfully downloaded plugins
|
---|
[3530] | 190 | *
|
---|
[3083] | 191 | * @return the list of successfully downloaded plugins
|
---|
| 192 | */
|
---|
| 193 | public Collection<PluginInformation> getFailedPlugins() {
|
---|
| 194 | return failed;
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | /**
|
---|
| 198 | * Replies the list of plugins whose download has failed
|
---|
[3530] | 199 | *
|
---|
[3083] | 200 | * @return the list of plugins whose download has failed
|
---|
| 201 | */
|
---|
| 202 | public Collection<PluginInformation> getDownloadedPlugins() {
|
---|
| 203 | return downloaded;
|
---|
| 204 | }
|
---|
| 205 | }
|
---|