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