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