001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.io.IOException;
007import java.io.InputStream;
008import java.text.MessageFormat;
009
010import org.openstreetmap.josm.data.osm.DataSet;
011import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
012import org.openstreetmap.josm.data.osm.PrimitiveId;
013import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
014import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
015import org.openstreetmap.josm.gui.progress.ProgressMonitor;
016import org.openstreetmap.josm.tools.CheckParameterUtil;
017
018/**
019 * OsmServerObjectReader reads an individual object from the OSM server.
020 *
021 * It can either download the object including or not including its immediate children.
022 * The former case is called a "full download".
023 *
024 * It can also download a specific version of the object (however, "full" download is not possible
025 * in that case).
026 *
027 */
028public class OsmServerObjectReader extends OsmServerReader {
029    /** the id of the object to download */
030    private final PrimitiveId id;
031    /** true if a full download is required, i.e. a download including the immediate children */
032    private final boolean full;
033    /** the specific version number, if required (incompatible with full), or -1 else */
034    private final int version;
035
036    /**
037     * Creates a new server object reader for a given id and a primitive type.
038     *
039     * @param id the object id. > 0 required.
040     * @param type the type. Must not be null.
041     * @param full true, if a full download is requested (i.e. a download including
042     * immediate children); false, otherwise
043     * @throws IllegalArgumentException if id <= 0
044     * @throws IllegalArgumentException if type is null
045     */
046    public OsmServerObjectReader(long id, OsmPrimitiveType type, boolean full) {
047        this(id, type, full, -1);
048    }
049
050    /**
051     * Creates a new server object reader for a given id and a primitive type.
052     *
053     * @param id the object id. > 0 required.
054     * @param type the type. Must not be null.
055     * @param version the specific version number, if required; -1, otherwise
056     * @throws IllegalArgumentException if id <= 0
057     * @throws IllegalArgumentException if type is null
058     */
059    public OsmServerObjectReader(long id, OsmPrimitiveType type, int version) {
060        this(id, type, false, version);
061    }
062
063    protected OsmServerObjectReader(long id, OsmPrimitiveType type, boolean full, int version) {
064        if (id <= 0)
065            throw new IllegalArgumentException(MessageFormat.format("Expected value > 0 for parameter ''{0}'', got {1}", "id", id));
066        CheckParameterUtil.ensureParameterNotNull(type, "type");
067        this.id = new SimplePrimitiveId(id, type);
068        this.full = full;
069        this.version = version;
070    }
071
072    /**
073     * Creates a new server object reader for an object with the given <code>id</code>
074     *
075     * @param id the object id. Must not be null. Unique id &gt; 0 required.
076     * @param full true, if a full download is requested (i.e. a download including
077     * immediate children); false, otherwise
078     * @throws IllegalArgumentException if id is null
079     * @throws IllegalArgumentException if id.getUniqueId() &lt;= 0
080     */
081    public OsmServerObjectReader(PrimitiveId id, boolean full) {
082        this(id, full, -1);
083    }
084
085    /**
086     * Creates a new server object reader for an object with the given <code>id</code>
087     *
088     * @param id the object id. Must not be null. Unique id &gt; 0 required.
089     * @param version the specific version number, if required; -1, otherwise
090     * @throws IllegalArgumentException if id is null
091     * @throws IllegalArgumentException if id.getUniqueId() &lt;= 0
092     */
093    public OsmServerObjectReader(PrimitiveId id, int version) {
094        this(id, false, version);
095    }
096
097    protected OsmServerObjectReader(PrimitiveId id, boolean full, int version) {
098        CheckParameterUtil.ensureThat(id.getUniqueId() > 0, "id > 0");
099        this.id = id;
100        this.full = full;
101        this.version = version;
102    }
103
104    /**
105     * Downloads and parses the data.
106     *
107     * @param progressMonitor the progress monitor. Set to {@link NullProgressMonitor#INSTANCE} if null
108     * @return the downloaded data
109     * @throws OsmTransferException if any error occurs during dialog with OSM API
110     */
111    @Override
112    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
113        if (progressMonitor == null) {
114            progressMonitor = NullProgressMonitor.INSTANCE;
115        }
116        progressMonitor.beginTask("", 1);
117        try {
118            progressMonitor.indeterminateSubTask(tr("Downloading OSM data..."));
119            StringBuilder sb = new StringBuilder();
120            sb.append(id.getType().getAPIName())
121              .append('/')
122              .append(id.getUniqueId());
123            if (full && id.getType() != OsmPrimitiveType.NODE) {
124                sb.append("/full");
125            } else if (version > 0) {
126                sb.append('/').append(version);
127            }
128
129            try (InputStream in = getInputStream(sb.toString(), progressMonitor.createSubTaskMonitor(1, true))) {
130                if (in == null)
131                    return null;
132                return OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
133            }
134        } catch (OsmTransferException e) {
135            if (cancel) return null;
136            throw e;
137        } catch (IOException | IllegalDataException e) {
138            if (cancel) return null;
139            throw new OsmTransferException(e);
140        } finally {
141            progressMonitor.finishTask();
142            activeConnection = null;
143        }
144    }
145}