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