001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions.downloadtasks;
003
004import java.util.ArrayList;
005import java.util.List;
006
007import org.openstreetmap.josm.data.ProjectionBounds;
008import org.openstreetmap.josm.io.XmlWriter;
009
010/**
011 * Common abstract implementation of other download tasks.
012 * @param <T> The downloaded data type
013 * @since 2322
014 */
015public abstract class AbstractDownloadTask<T> implements DownloadTask {
016    private final List<Object> errorMessages;
017    private boolean canceled;
018    private boolean failed;
019    protected T downloadedData;
020    protected boolean zoomAfterDownload = true;
021
022    /**
023     * Constructs a new {@code AbstractDownloadTask}.
024     */
025    public AbstractDownloadTask() {
026        errorMessages = new ArrayList<>();
027    }
028
029    /**
030     * Determines if the download task has been canceled.
031     * @return {@code true} if the download task has been canceled
032     */
033    public boolean isCanceled() {
034        return canceled;
035    }
036
037    /**
038     * Marks this download task as canceled.
039     * @param canceled {@code true} to mark this download task as canceled
040     */
041    public void setCanceled(boolean canceled) {
042        this.canceled = canceled;
043    }
044
045    /**
046     * Determines if the download task has failed.
047     * @return {@code true} if the download task has failed
048     */
049    public boolean isFailed() {
050        return failed;
051    }
052
053    /**
054     * Marks this download task as failed.
055     * @param failed {@code true} to mark this download task as failed
056     */
057    public void setFailed(boolean failed) {
058        this.failed = failed;
059    }
060
061    protected final void rememberErrorMessage(String message) {
062        errorMessages.add(message);
063    }
064
065    protected final void rememberException(Exception exception) {
066        errorMessages.add(exception);
067    }
068
069    protected final void rememberDownloadedData(T data) {
070        this.downloadedData = data;
071    }
072
073    /**
074     * Replies the downloaded data.
075     * @return The downloaded data.
076     */
077    public final T getDownloadedData() {
078        return downloadedData;
079    }
080
081    @Override
082    public final void setZoomAfterDownload(boolean zoomAfterDownload) {
083        this.zoomAfterDownload = zoomAfterDownload;
084    }
085
086    @Override
087    public List<Object> getErrorObjects() {
088        return errorMessages;
089    }
090
091    @Override
092    public String acceptsDocumentationSummary() {
093        StringBuilder buff = new StringBuilder(128)
094            .append("<tr><td>")
095            .append(getTitle())
096            .append(":</td><td>");
097        String[] patterns = getPatterns();
098        if (patterns.length > 0) {
099            buff.append("<ul>");
100            for (String pattern: patterns) {
101                buff.append("<li>")
102                    .append(XmlWriter.encode(pattern))
103                    .append("</li>");
104            }
105            buff.append("</ul>");
106        }
107        buff.append("</td></tr>");
108        return buff.toString();
109    }
110
111    /**
112     * Determines if the given URL is accepted by {@link #getPatterns}.
113     * Can be overridden for more complex checking logic.
114     * @param url URL to donwload
115     * @return {@code true} if this URL is accepted
116     */
117    public boolean acceptsUrl(String url) {
118        if (url == null)
119            return false;
120        for (String p: getPatterns()) {
121            if (url.matches(p)) {
122                return true;
123            }
124        }
125        return false;
126    }
127
128    /**
129     * Check / decide if the task is safe for remotecontrol.
130     *
131     * Keep in mind that a potential attacker has full control over the content
132     * of the file that will be downloaded.
133     * If it is possible to run arbitrary code or write to the local file
134     * system, then the task is (obviously) not save for remote execution.
135     *
136     * The default value is false = unsafe. Override in a subclass to
137     * allow running the task via remotecontol.
138     *
139     * @return true if it is safe to download and open any file of the
140     * corresponding format, false otherwise
141     */
142    public boolean isSafeForRemotecontrolRequests() {
143        return false;
144    }
145
146    @Override
147    public boolean acceptsUrl(String url, boolean isRemotecontrol) {
148        if (isRemotecontrol && !isSafeForRemotecontrolRequests())
149            return false;
150        return acceptsUrl(url);
151    }
152
153    // Default name to keep old plugins compatible
154    @Override
155    public String getTitle() {
156        return getClass().getName();
157    }
158
159    @Override
160    public String toString() {
161        return this.getTitle();
162    }
163
164    // Default pattern to keep old plugins compatible
165    @Override
166    public String[] getPatterns() {
167        return new String[]{};
168    }
169
170    /**
171     * Returns the projection bounds of downloaded data.
172     * @return the projection bounds of downloaded data or {@code null}
173     * @since 11774
174     */
175    public ProjectionBounds getDownloadProjectionBounds() {
176        return null;
177    }
178}