001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005import static org.openstreetmap.josm.tools.I18n.trn;
006
007import java.io.IOException;
008import java.io.InputStream;
009import java.text.MessageFormat;
010import java.util.ArrayList;
011import java.util.Collection;
012import java.util.Collections;
013import java.util.List;
014
015import org.openstreetmap.josm.Main;
016import org.openstreetmap.josm.data.osm.Changeset;
017import org.openstreetmap.josm.data.osm.ChangesetDataSet;
018import org.openstreetmap.josm.data.osm.DataSet;
019import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
020import org.openstreetmap.josm.gui.progress.ProgressMonitor;
021import org.openstreetmap.josm.tools.CheckParameterUtil;
022import org.openstreetmap.josm.tools.XmlParsingException;
023
024/**
025 * Reads the history of an {@link org.openstreetmap.josm.data.osm.OsmPrimitive} from the OSM API server.
026 *
027 */
028public class OsmServerChangesetReader extends OsmServerReader {
029
030    /**
031     * Constructs a new {@code OsmServerChangesetReader}.
032     */
033    public OsmServerChangesetReader() {
034        setDoAuthenticate(false);
035    }
036
037    /**
038     * don't use - not implemented!
039     */
040    @Override
041    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
042        return null;
043    }
044
045    protected final InputStream getChangesetInputStream(long id, boolean includeDiscussion, ProgressMonitor monitor)
046            throws OsmTransferException {
047        StringBuilder sb = new StringBuilder(48).append("changeset/").append(id);
048        if (includeDiscussion) {
049            sb.append("?include_discussion=true");
050        }
051        return getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
052    }
053
054    /**
055     * Queries a list
056     * @param query  the query specification. Must not be null.
057     * @param monitor a progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
058     * @return the list of changesets read from the server
059     * @throws IllegalArgumentException if query is null
060     * @throws OsmTransferException if something goes wrong w
061     */
062    public List<Changeset> queryChangesets(ChangesetQuery query, ProgressMonitor monitor) throws OsmTransferException {
063        CheckParameterUtil.ensureParameterNotNull(query, "query");
064        List<Changeset> result = null;
065        if (monitor == null) {
066            monitor = NullProgressMonitor.INSTANCE;
067        }
068        try {
069            monitor.beginTask(tr("Reading changesets..."));
070            StringBuilder sb = new StringBuilder();
071            sb.append("changesets?").append(query.getQueryString());
072            try (InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true))) {
073                if (in == null)
074                    return Collections.emptyList();
075                monitor.indeterminateSubTask(tr("Downloading changesets ..."));
076                result = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
077            } catch (IOException e) {
078                Main.warn(e);
079            }
080        } catch (OsmTransferException e) {
081            throw e;
082        } catch (IllegalDataException e) {
083            throw new OsmTransferException(e);
084        } finally {
085            monitor.finishTask();
086        }
087        return result;
088    }
089
090    /**
091     * Reads the changeset with id <code>id</code> from the server.
092     *
093     * @param id the changeset id. id &gt; 0 required.
094     * @param includeDiscussion determines if discussion comments must be downloaded or not
095     * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
096     * @return the changeset read
097     * @throws OsmTransferException if something goes wrong
098     * @throws IllegalArgumentException if id &lt;= 0
099     * @since 7704
100     */
101    public Changeset readChangeset(long id, boolean includeDiscussion, ProgressMonitor monitor) throws OsmTransferException {
102        if (id <= 0)
103            throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected. Got ''{1}''.", "id", id));
104        if (monitor == null) {
105            monitor = NullProgressMonitor.INSTANCE;
106        }
107        Changeset result = null;
108        try {
109            monitor.beginTask(tr("Reading changeset {0} ...", id));
110            try (InputStream in = getChangesetInputStream(id, includeDiscussion, monitor)) {
111                if (in == null)
112                    return null;
113                monitor.indeterminateSubTask(tr("Downloading changeset {0} ...", id));
114                List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
115                if (changesets == null || changesets.isEmpty())
116                    return null;
117                result = changesets.get(0);
118            } catch (IOException e) {
119                Main.warn(e);
120            }
121        } catch (OsmTransferException e) {
122            throw e;
123        } catch (IllegalDataException e) {
124            throw new OsmTransferException(e);
125        } finally {
126            monitor.finishTask();
127        }
128        return result;
129    }
130
131    /**
132     * Reads the changesets with id <code>ids</code> from the server.
133     *
134     * @param ids the list of ids. Ignored if null. Only load changesets for ids &gt; 0.
135     * @param includeDiscussion determines if discussion comments must be downloaded or not
136     * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
137     * @return the changeset read
138     * @throws OsmTransferException if something goes wrong
139     * @throws IllegalArgumentException if id &lt;= 0
140     * @since 7704
141     */
142    public List<Changeset> readChangesets(Collection<Integer> ids, boolean includeDiscussion, ProgressMonitor monitor)
143            throws OsmTransferException {
144        if (ids == null)
145            return Collections.emptyList();
146        if (monitor == null) {
147            monitor = NullProgressMonitor.INSTANCE;
148        }
149        try {
150            monitor.beginTask(trn("Downloading {0} changeset ...", "Downloading {0} changesets ...", ids.size(), ids.size()));
151            monitor.setTicksCount(ids.size());
152            List<Changeset> ret = new ArrayList<>();
153            int i = 0;
154            for (int id : ids) {
155                if (id <= 0) {
156                    continue;
157                }
158                i++;
159                try (InputStream in = getChangesetInputStream(id, includeDiscussion, monitor)) {
160                    if (in == null)
161                        return null;
162                    monitor.indeterminateSubTask(tr("({0}/{1}) Downloading changeset {2} ...", i, ids.size(), id));
163                    List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
164                    if (changesets == null || changesets.isEmpty()) {
165                        continue;
166                    }
167                    ret.addAll(changesets);
168                } catch (IOException e) {
169                    Main.warn(e);
170                }
171                monitor.worked(1);
172            }
173            return ret;
174        } catch (OsmTransferException e) {
175            throw e;
176        } catch (IllegalDataException e) {
177            throw new OsmTransferException(e);
178        } finally {
179            monitor.finishTask();
180        }
181    }
182
183    /**
184     * Downloads the content of a changeset
185     *
186     * @param id the changeset id. &gt; 0 required.
187     * @param monitor the progress monitor. {@link NullProgressMonitor#INSTANCE} assumed if null.
188     * @return the changeset content
189     * @throws IllegalArgumentException if id &lt;= 0
190     * @throws OsmTransferException if something went wrong
191     */
192    public ChangesetDataSet downloadChangeset(int id, ProgressMonitor monitor) throws OsmTransferException {
193        if (id <= 0)
194            throw new IllegalArgumentException(
195                    MessageFormat.format("Expected value of type integer > 0 for parameter ''{0}'', got {1}", "id", id));
196        if (monitor == null) {
197            monitor = NullProgressMonitor.INSTANCE;
198        }
199        ChangesetDataSet result = null;
200        try {
201            monitor.beginTask(tr("Downloading changeset content"));
202            StringBuilder sb = new StringBuilder(32).append("changeset/").append(id).append("/download");
203            try (InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true))) {
204                if (in == null)
205                    return null;
206                monitor.setCustomText(tr("Downloading content for changeset {0} ...", id));
207                OsmChangesetContentParser parser = new OsmChangesetContentParser(in);
208                result = parser.parse(monitor.createSubTaskMonitor(1, true));
209            } catch (IOException e) {
210                Main.warn(e);
211            }
212        } catch (XmlParsingException e) {
213            throw new OsmTransferException(e);
214        } finally {
215            monitor.finishTask();
216        }
217        return result;
218    }
219}