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();
048        sb.append("changeset/").append(id);
049        if (includeDiscussion) {
050            sb.append("?include_discussion=true");
051        }
052        return getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
053    }
054
055    /**
056     * Queries a list
057     * @param query  the query specification. Must not be null.
058     * @param monitor a progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
059     * @return the list of changesets read from the server
060     * @throws IllegalArgumentException thrown if query is null
061     * @throws OsmTransferException thrown if something goes wrong w
062     */
063    public List<Changeset> queryChangesets(ChangesetQuery query, ProgressMonitor monitor) throws OsmTransferException {
064        CheckParameterUtil.ensureParameterNotNull(query, "query");
065        List<Changeset> result = null;
066        if (monitor == null) {
067            monitor = NullProgressMonitor.INSTANCE;
068        }
069        try {
070            monitor.beginTask(tr("Reading changesets..."));
071            StringBuilder sb = new StringBuilder();
072            sb.append("changesets?").append(query.getQueryString());
073            try (InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true))) {
074                if (in == null)
075                    return null;
076                monitor.indeterminateSubTask(tr("Downloading changesets ..."));
077                result = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
078            } catch (IOException e) {
079                Main.warn(e);
080            }
081        } catch(OsmTransferException e) {
082            throw e;
083        } catch(IllegalDataException e) {
084            throw new OsmTransferException(e);
085        } finally {
086            monitor.finishTask();
087        }
088        return result;
089    }
090
091    /**
092     * Reads the changeset with id <code>id</code> from the server.
093     *
094     * @param id the changeset id. id &gt; 0 required.
095     * @param includeDiscussion determines if discussion comments must be downloaded or not
096     * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
097     * @return the changeset read
098     * @throws OsmTransferException thrown if something goes wrong
099     * @throws IllegalArgumentException if id &lt;= 0
100     * @since 7704
101     */
102    public Changeset readChangeset(long id, boolean includeDiscussion, ProgressMonitor monitor) throws OsmTransferException {
103        if (id <= 0)
104            throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0 expected. Got ''{1}''.", "id", id));
105        if (monitor == null) {
106            monitor = NullProgressMonitor.INSTANCE;
107        }
108        Changeset result = null;
109        try {
110            monitor.beginTask(tr("Reading changeset {0} ...",id));
111            try (InputStream in = getChangesetInputStream(id, includeDiscussion, monitor)) {
112                if (in == null)
113                    return null;
114                monitor.indeterminateSubTask(tr("Downloading changeset {0} ...", id));
115                List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
116                if (changesets == null || changesets.isEmpty())
117                    return null;
118                result = changesets.get(0);
119            } catch (IOException e) {
120                Main.warn(e);
121            }
122        } catch(OsmTransferException e) {
123            throw e;
124        } catch(IllegalDataException e) {
125            throw new OsmTransferException(e);
126        } finally {
127            monitor.finishTask();
128        }
129        return result;
130    }
131
132    /**
133     * Reads the changesets with id <code>ids</code> from the server.
134     *
135     * @param ids the list of ids. Ignored if null. Only load changesets for ids &gt; 0.
136     * @param includeDiscussion determines if discussion comments must be downloaded or not
137     * @param monitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
138     * @return the changeset read
139     * @throws OsmTransferException thrown if something goes wrong
140     * @throws IllegalArgumentException if id &lt;= 0
141     * @since 7704
142     */
143    public List<Changeset> readChangesets(Collection<Integer> ids, boolean includeDiscussion, ProgressMonitor monitor) 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 thrown if id &lt;= 0
190     * @throws OsmTransferException thrown if something went wrong
191     */
192    public ChangesetDataSet downloadChangeset(int id, ProgressMonitor monitor) throws IllegalArgumentException, OsmTransferException {
193        if (id <= 0)
194            throw new IllegalArgumentException(MessageFormat.format("Expected value of type integer > 0 for parameter ''{0}'', got {1}", "id", id));
195        if (monitor == null) {
196            monitor = NullProgressMonitor.INSTANCE;
197        }
198        ChangesetDataSet result = null;
199        try {
200            monitor.beginTask(tr("Downloading changeset content"));
201            StringBuilder sb = new StringBuilder();
202            sb.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}