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