Ignore:
Timestamp:
2009-09-06T23:07:33+02:00 (15 years ago)
Author:
Gubaer
Message:

new: rewrite of CombineWay action
new: conflict resolution dialog for CombineWay, including conflicts for different relation memberships
cleanup: cleanup in OsmReader, reduces memory footprint and reduces parsing time
cleanup: made most of the public fields in OsmPrimitive @deprecated, added accessors and changed the code
cleanup: replaced usages of @deprecated constructors for ExtendedDialog
fixed #3208: Combine ways brokes relation order

WARNING: this changeset touches a lot of code all over the code base. "latest" might become slightly unstable in the next days. Also experience incompatibility issues with plugins in the next few days.

Location:
trunk/src/org/openstreetmap/josm/io
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/DiffResultReader.java

    r2039 r2070  
    9494    public void visit(Node n) {
    9595        String key = "node:" + (newIdMap.containsKey(n) ? newIdMap.get(n) : n.getId());
    96         System.out.println("key: "+key);
    9796        Long[] nv = versions.get(key);
    9897        if (nv != null) {
    9998            processed.add(n);
    10099            if (!n.isDeleted()) {
    101                 n.id = nv[0]; n.version = nv[1].intValue();
     100                n.setOsmId(nv[0], nv[1].intValue());
    102101            }
    103102        }
     
    109108            processed.add(w);
    110109            if (!w.isDeleted()) {
    111                 w.id = nv[0]; w.version = nv[1].intValue();
     110                w.setOsmId(nv[0], nv[1].intValue());
    112111            }
    113112        }
     
    119118            processed.add(r);
    120119            if (!r.isDeleted()) {
    121                 r.id = nv[0]; r.version = nv[1].intValue();
     120                r.setOsmId(nv[0], nv[1].intValue());
    122121            }
    123122        }
  • trunk/src/org/openstreetmap/josm/io/FileImporter.java

    r1637 r2070  
    2121    }
    2222
    23     public void importData(File file) throws IOException {
     23    public void importData(File file) throws IOException, IllegalDataException {
    2424        throw new IOException(tr("Could not read \"{0}\"", file.getName()));
    2525    }
  • trunk/src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java

    r2025 r2070  
    204204        remember(relation.getId(), OsmPrimitiveType.RELATION);
    205205        for (RelationMember member : relation.getMembers()) {
    206             if (OsmPrimitiveType.from(member.member).equals(OsmPrimitiveType.RELATION)) {
     206            if (OsmPrimitiveType.from(member.getMember()).equals(OsmPrimitiveType.RELATION)) {
    207207                // avoid infinite recursion in case of cyclic dependencies in relations
    208208                //
    209                 if (relations.contains(member.member.getId())) {
     209                if (relations.contains(member.getMember().getId())) {
    210210                    continue;
    211211                }
     
    325325        progressMonitor.subTask(tr("Downloading OSM data..."));
    326326        try {
    327             final OsmReader osm = OsmReader.parseDataSetOsm(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    328             merge(osm.getDs());
     327
     328            merge(
     329                    OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false))
     330            );
    329331        } catch(Exception e) {
    330332            throw new OsmTransferException(e);
     
    348350        progressMonitor.subTask(tr("Downloading OSM data..."));
    349351        try {
    350             final OsmReader osm = OsmReader.parseDataSetOsm(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    351             merge(osm.getDs());
     352            merge(
     353                    OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false))
     354            );
    352355        } catch(Exception e) {
    353356            throw new OsmTransferException(e);
  • trunk/src/org/openstreetmap/josm/io/OsmApi.java

    r2061 r2070  
    233233        try {
    234234            ret = sendRequest("PUT", OsmPrimitiveType.from(osm).getAPIName()+"/create", toXml(osm, true),monitor);
    235             osm.id = Long.parseLong(ret.trim());
    236             osm.version = 1;
     235            osm.setOsmId(Long.parseLong(ret.trim()), 1);
    237236        } catch(NumberFormatException e){
    238237            throw new OsmTransferException(tr("unexpected format of id replied by the server, got ''{0}''", ret));
     
    258257            try {
    259258                ret = sendRequest("PUT", OsmPrimitiveType.from(osm).getAPIName()+"/" + osm.getId(), toXml(osm, true), monitor);
    260                 osm.version = Integer.parseInt(ret.trim());
     259                osm.setOsmId(osm.getId(), Integer.parseInt(ret.trim()));
    261260            } catch(NumberFormatException e) {
    262261                throw new OsmTransferException(tr("unexpected format of new version of modified primitive ''{0}'', got ''{1}''", osm.getId(), ret));
     
    341340                    return;
    342341                }
    343                 changeset.id = this.changeset.getId();
    344                 this.changeset.cloneFrom(changeset);
     342                this.changeset.setKeys(changeset.getKeys());
    345343                progressMonitor.setCustomText(tr("Updating changeset {0}...", changeset.getId()));
    346344                sendRequest(
     
    473471     */
    474472    private String sendRequest(String requestMethod, String urlSuffix,String requestBody, ProgressMonitor monitor) throws OsmTransferException {
    475 
    476473        StringBuffer responseBody = new StringBuffer();
    477474
  • trunk/src/org/openstreetmap/josm/io/OsmBzip2Importer.java

    r2001 r2070  
    1111import org.apache.tools.bzip2.CBZip2InputStream;
    1212import org.openstreetmap.josm.actions.ExtensionFileFilter;
    13 import org.xml.sax.SAXException;
    1413
    1514public class OsmBzip2Importer extends OsmImporter {
     
    2120
    2221    @Override
    23     public void importData(File file) throws IOException {
     22    public void importData(File file) throws IOException, IllegalDataException {
    2423        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
    2524        int b = bis.read();
    26         if (b != 'B') {
     25        if (b != 'B')
    2726            throw new IOException(tr("Invalid bz2 file."));
    28         }
    2927        b = bis.read();
    30         if (b != 'Z') {
     28        if (b != 'Z')
    3129            throw new IOException(tr("Invalid bz2 file."));
    32         }
    3330        CBZip2InputStream in = new CBZip2InputStream(bis);
    34 
    35         try {
    36             importData(in, file);
    37         } catch (SAXException e) {
    38             e.printStackTrace();
    39             throw new IOException(tr("Could not read \"{0}\"", file.getName()));
    40         }
     31        importData(in, file);
    4132    }
    4233}
  • trunk/src/org/openstreetmap/josm/io/OsmGzipImporter.java

    r1653 r2070  
    1010
    1111import org.openstreetmap.josm.actions.ExtensionFileFilter;
    12 import org.xml.sax.SAXException;
    1312
    1413public class OsmGzipImporter extends OsmImporter {
     
    1918
    2019    @Override
    21     public void importData(File file) throws IOException {
     20    public void importData(File file) throws IOException, IllegalDataException {
    2221        GZIPInputStream in = new GZIPInputStream(new FileInputStream(file));
    23         try {
    24             importData(in, file);
    25         } catch (SAXException e) {
    26             e.printStackTrace();
    27             throw new IOException(tr("Could not read \"{0}\"", file.getName()));
    28         }
     22        importData(in, file);
    2923    }
    3024}
  • trunk/src/org/openstreetmap/josm/io/OsmImporter.java

    r2050 r2070  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.HeadlessException;
    76import java.io.File;
    87import java.io.FileInputStream;
     
    1817import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    1918import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
    20 import org.xml.sax.SAXException;
    2119
    2220public class OsmImporter extends FileImporter {
     
    3028    }
    3129
    32     @Override public void importData(File file) throws IOException {
     30    @Override public void importData(File file) throws IOException, IllegalDataException {
    3331        try {
    3432            FileInputStream in = new FileInputStream(file);
    3533            importData(in, file);
    36         } catch (HeadlessException e) {
    37             e.printStackTrace();
    38             throw new IOException(tr("Could not read \"{0}\"", file.getName()));
    3934        } catch (FileNotFoundException e) {
    4035            e.printStackTrace();
    4136            throw new IOException(tr("File \"{0}\" does not exist", file.getName()));
    42         } catch (SAXException e) {
    43             e.printStackTrace();
    44             throw new IOException(tr("Parsing file \"{0}\" failed", file.getName()));
    4537        }
    4638    }
    4739
    48     protected void importData(InputStream in, File associatedFile) throws SAXException, IOException {
    49         OsmReader osm = OsmReader.parseDataSetOsm(in, NullProgressMonitor.INSTANCE);
    50         DataSet dataSet = osm.getDs();
     40    protected void importData(InputStream in, File associatedFile) throws IllegalDataException {
     41        DataSet dataSet = OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
    5142        final OsmDataLayer layer = new OsmDataLayer(dataSet, associatedFile.getName(), associatedFile);
    5243        // FIXME: remove UI stuff from IO subsystem
  • trunk/src/org/openstreetmap/josm/io/OsmReader.java

    r1951 r2070  
    1 // License: GPL. Copyright 2007 by Immanuel Scholz and others
    21package org.openstreetmap.josm.io;
    32
    43import static org.openstreetmap.josm.tools.I18n.tr;
    54
    6 import java.io.IOException;
    75import java.io.InputStream;
    86import java.io.InputStreamReader;
     
    1412import java.util.List;
    1513import java.util.Map;
    16 import java.util.Map.Entry;
    1714import java.util.logging.Logger;
    1815
     
    3431import org.xml.sax.Attributes;
    3532import org.xml.sax.InputSource;
     33import org.xml.sax.Locator;
    3634import org.xml.sax.SAXException;
    3735import org.xml.sax.helpers.DefaultHandler;
     
    4038 * Parser for the Osm Api. Read from an input stream and construct a dataset out of it.
    4139 *
    42  * Reading process takes place in three phases. During the first phase (including xml parse),
    43  * all nodes are read and stored. Other information than nodes are stored in a raw list
    44  *
    45  * The second phase read all ways out of the remaining objects in the raw list.
    46  *
    47  * @author Imi
    4840 */
    4941public class OsmReader {
     
    5446     */
    5547    private DataSet ds = new DataSet();
    56     public DataSet getDs() { return ds; }
    57 
    58     /**
    59      * All read nodes after phase 1.
    60      */
    61     private Map<Long, Node> nodes = new HashMap<Long, Node>();
     48
     49    /**
     50     * Replies the parsed data set
     51     *
     52     * @return the parsed data set
     53     */
     54    public DataSet getDataSet() {
     55        return ds;
     56    }
     57
     58    /** the map from external ids to read OsmPrimitives. External ids are
     59     * longs too, but in contrast to internal ids negative values are used
     60     * to identify primitives unknown to the OSM server
     61     *
     62     * The keys are strings composed as follows
     63     * <ul>
     64     *   <li>"n" + id  for nodes</li>
     65     *   <li>"w" + id  for nodes</li>
     66     *   <li>"r" + id  for nodes</li>
     67     * </ul>
     68     */
     69    private Map<String, OsmPrimitive> externalIdMap = new HashMap<String, OsmPrimitive>();
    6270
    6371
     
    6977     */
    7078    private OsmReader() {
     79        externalIdMap = new HashMap<String, OsmPrimitive>();
    7180    }
    7281
    7382    private static class OsmPrimitiveData {
    7483        public long id = 0;
    75         public Map<String,String> keys = new HashMap<String, String>();
    7684        public boolean modified = false;
    77         public boolean selected = false;
    7885        public boolean deleted = false;
    7986        public Date timestamp = new Date();
    8087        public User user = null;
    8188        public boolean visible = true;
    82         public int version = -1;
     89        public int version = 0;
    8390        public LatLon latlon = new LatLon(0,0);
     91        private OsmPrimitive primitive;
    8492
    8593        public void copyTo(OsmPrimitive osm) {
    86             osm.id = id;
    87             osm.setKeys(keys);
    88             osm.modified = modified;
    89             osm.setSelected(selected);
    90             osm.deleted = deleted;
     94            osm.setModified(modified);
     95            osm.setDeleted(deleted);
     96            //  id < 0 possible if read from a file
     97            if (id <= 0) {
     98                osm.clearOsmId();
     99            } else {
     100                osm.setOsmId(id, version);
     101            }
    91102            osm.setTimestamp(timestamp);
    92103            osm.user = user;
    93             osm.visible = visible;
    94             osm.version = version;
     104            osm.setVisible(visible);
    95105            osm.mappaintStyle = null;
    96106        }
    97107
    98108        public Node createNode() {
    99             Node node = new Node(latlon);
     109            Node node = new Node();
     110            node.setCoor(latlon);
    100111            copyTo(node);
     112            primitive = node;
    101113            return node;
    102114        }
    103115
    104116        public Way createWay() {
    105             Way way = new Way(id);
     117            Way way = new Way();
    106118            copyTo(way);
     119            primitive = way;
    107120            return way;
    108121        }
    109 
    110122        public Relation createRelation() {
    111             Relation rel = new Relation(id);
    112             copyTo(rel);
    113             return rel;
     123            Relation relation= new Relation();
     124            copyTo(relation);
     125            primitive = relation;
     126            return relation;
     127        }
     128
     129        public void rememberTag(String key, String value) {
     130            primitive.put(key, value);
    114131        }
    115132    }
     
    128145     * Data structure for the remaining way objects
    129146     */
    130     private Map<OsmPrimitiveData, Collection<Long>> ways = new HashMap<OsmPrimitiveData, Collection<Long>>();
     147    private Map<Long, Collection<Long>> ways = new HashMap<Long, Collection<Long>>();
    131148
    132149    /**
    133150     * Data structure for relation objects
    134151     */
    135     private Map<OsmPrimitiveData, Collection<RelationMemberData>> relations = new HashMap<OsmPrimitiveData, Collection<RelationMemberData>>();
     152    private Map<Long, Collection<RelationMemberData>> relations = new HashMap<Long, Collection<RelationMemberData>>();
     153
     154    static public class OsmDataParsingException extends SAXException {
     155        private int columnNumber;
     156        private int lineNumber;
     157
     158        public OsmDataParsingException() {
     159            super();
     160        }
     161
     162        public OsmDataParsingException(Exception e) {
     163            super(e);
     164        }
     165
     166        public OsmDataParsingException(String message, Exception e) {
     167            super(message, e);
     168        }
     169
     170        public OsmDataParsingException(String message) {
     171            super(message);
     172        }
     173
     174        public OsmDataParsingException rememberLocation(Locator locator) {
     175            if (locator == null) return this;
     176            this.columnNumber = locator.getColumnNumber();
     177            this.lineNumber = locator.getLineNumber();
     178            return this;
     179        }
     180
     181        @Override
     182        public String getMessage() {
     183            String msg = super.getMessage();
     184            if (lineNumber == 0 && columnNumber == 0)
     185                return msg;
     186            if (msg == null) {
     187                msg = getClass().getName();
     188            }
     189            msg = msg + " " + tr("(at line {0}, column {1})", lineNumber, columnNumber);
     190            return msg;
     191        }
     192
     193        public int getColumnNumber() {
     194            return columnNumber;
     195        }
     196
     197        public int getLineNumber() {
     198            return lineNumber;
     199        }
     200    }
    136201
    137202    private class Parser extends DefaultHandler {
     203        private Locator locator;
     204
     205        @Override
     206        public void setDocumentLocator(Locator locator) {
     207            this.locator = locator;
     208        }
     209
     210        protected void throwException(String msg) throws OsmDataParsingException{
     211            throw new OsmDataParsingException(msg).rememberLocation(locator);
     212        }
    138213        /**
    139214         * The current osm primitive to be read.
     
    143218
    144219        @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
    145             try {
    146                 if (qName.equals("osm")) {
    147                     if (atts == null)
    148                         throw new SAXException(tr("Unknown version"));
    149                     String v = atts.getValue("version");
    150                     if (v == null)
    151                         throw new SAXException(tr("Version number missing from OSM data"));
    152                     if (!(v.equals("0.5") || v.equals("0.6")))
    153                         throw new SAXException(tr("Unknown version: {0}", v));
    154                     // save generator attribute for later use when creating DataSource objects
    155                     generator = atts.getValue("generator");
    156                     ds.version = v;
    157 
    158                 } else if (qName.equals("bounds")) {
    159                     // new style bounds.
    160                     String minlon = atts.getValue("minlon");
    161                     String minlat = atts.getValue("minlat");
    162                     String maxlon = atts.getValue("maxlon");
    163                     String maxlat = atts.getValue("maxlat");
    164                     String origin = atts.getValue("origin");
    165                     if (minlon != null && maxlon != null && minlat != null && maxlat != null) {
    166                         if (origin == null) {
    167                             origin = generator;
    168                         }
    169                         Bounds bounds = new Bounds(
    170                                 new LatLon(Double.parseDouble(minlat), Double.parseDouble(minlon)),
    171                                 new LatLon(Double.parseDouble(maxlat), Double.parseDouble(maxlon)));
    172                         DataSource src = new DataSource(bounds, origin);
    173                         ds.dataSources.add(src);
     220            if (qName.equals("osm")) {
     221                if (atts == null) {
     222                    throwException(tr("Missing mandatory attribute ''{0}'' of XML element {1}", "version", "osm"));
     223                }
     224                String v = atts.getValue("version");
     225                if (v == null) {
     226                    throwException(tr("Missing mandatory attribute ''{0}''", "version"));
     227                }
     228                if (!(v.equals("0.5") || v.equals("0.6"))) {
     229                    throwException(tr("Unsupported version: {0}", v));
     230                }
     231                // save generator attribute for later use when creating DataSource objects
     232                generator = atts.getValue("generator");
     233                ds.version = v;
     234
     235            } else if (qName.equals("bounds")) {
     236                // new style bounds.
     237                String minlon = atts.getValue("minlon");
     238                String minlat = atts.getValue("minlat");
     239                String maxlon = atts.getValue("maxlon");
     240                String maxlat = atts.getValue("maxlat");
     241                String origin = atts.getValue("origin");
     242                if (minlon != null && maxlon != null && minlat != null && maxlat != null) {
     243                    if (origin == null) {
     244                        origin = generator;
    174245                    }
    175 
    176                     // ---- PARSING NODES AND WAYS ----
    177 
    178                 } else if (qName.equals("node")) {
    179                     current = new OsmPrimitiveData();
    180                     current.latlon = new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon"));
    181                     readCommon(atts, current);
    182                 } else if (qName.equals("way")) {
    183                     current = new OsmPrimitiveData();
    184                     readCommon(atts, current);
    185                     ways.put(current, new ArrayList<Long>());
    186                 } else if (qName.equals("nd")) {
    187                     Collection<Long> list = ways.get(current);
    188                     if (list == null)
    189                         throw new SAXException(tr("Found <nd> element in non-way."));
    190                     long id = getLong(atts, "ref");
    191                     if (id == 0)
    192                         throw new SAXException(tr("<nd> has zero ref"));
    193                     list.add(id);
    194 
    195                     // ---- PARSING RELATIONS ----
    196 
    197                 } else if (qName.equals("relation")) {
    198                     current = new OsmPrimitiveData();
    199                     readCommon(atts, current);
    200                     relations.put(current, new LinkedList<RelationMemberData>());
    201                 } else if (qName.equals("member")) {
    202                     Collection<RelationMemberData> list = relations.get(current);
    203                     if (list == null)
    204                         throw new SAXException(tr("Found <member> element in non-relation."));
    205                     RelationMemberData emd = new RelationMemberData();
    206                     String value = atts.getValue("ref");
    207                     if (value == null)
    208                         throw new SAXException(tr("Missing attribute \"ref\" on member in relation {0}",current.id));
    209                     try {
    210                         emd.id = Long.parseLong(value);
    211                     } catch(NumberFormatException e) {
    212                         throw new SAXException(tr("Illegal value for attribute \"ref\" on member in relation {0}, got {1}", Long.toString(current.id),value));
    213                     }
    214                     value = atts.getValue("type");
    215                     if (value == null)
    216                         throw new SAXException(tr("Missing attribute \"type\" on member {0} in relation {1}", Long.toString(emd.id), Long.toString(current.id)));
    217                     if (! (value.equals("way") || value.equals("node") || value.equals("relation")))
    218                         throw new SAXException(tr("Unexpected \"type\" on member {0} in relation {1}, got {2}.", Long.toString(emd.id), Long.toString(current.id), value));
    219                     emd.type= value;
    220                     value = atts.getValue("role");
    221                     emd.role = value;
    222 
    223                     if (emd.id == 0)
    224                         throw new SAXException(tr("Incomplete <member> specification with ref=0"));
    225 
    226                     list.add(emd);
    227 
    228                     // ---- PARSING TAGS (applicable to all objects) ----
    229 
    230                 } else if (qName.equals("tag")) {
    231                     String key = atts.getValue("k");
    232                     String value = atts.getValue("v");
    233                     current.keys.put(key,value);
    234                 }
    235             } catch (NumberFormatException x) {
    236                 x.printStackTrace(); // SAXException does not chain correctly
    237                 throw new SAXException(x.getMessage(), x);
    238             } catch (NullPointerException x) {
    239                 x.printStackTrace(); // SAXException does not chain correctly
    240                 throw new SAXException(tr("NullPointerException, possibly some missing tags."), x);
    241             }
    242         }
    243 
    244         @Override
    245         public void endElement(String uri, String localName, String qName) throws SAXException {
    246             if (qName.equals("node")) {
    247                 nodes.put(current.id, current.createNode());
     246                    Bounds bounds = new Bounds(
     247                            new LatLon(Double.parseDouble(minlat), Double.parseDouble(minlon)),
     248                            new LatLon(Double.parseDouble(maxlat), Double.parseDouble(maxlon)));
     249                    DataSource src = new DataSource(bounds, origin);
     250                    ds.dataSources.add(src);
     251                } else {
     252                    throwException(tr(
     253                            "Missing manadatory attributes on element ''bounds''. Got minlon=''{0}'',minlat=''{1}00,maxlon=''{3}'',maxlat=''{4}'', origin=''{5}''",
     254                            minlon, minlat, maxlon, maxlat, origin
     255                    ));
     256                }
     257
     258                // ---- PARSING NODES AND WAYS ----
     259
     260            } else if (qName.equals("node")) {
     261                current = new OsmPrimitiveData();
     262                current.latlon = new LatLon(getDouble(atts, "lat"), getDouble(atts, "lon"));
     263                readCommon(atts, current);
     264                Node n = current.createNode();
     265                externalIdMap.put("n"+current.id, n);
     266            } else if (qName.equals("way")) {
     267                current = new OsmPrimitiveData();
     268                readCommon(atts, current);
     269                Way w = current.createWay();
     270                externalIdMap.put("w"+current.id, w);
     271                ways.put(current.id, new ArrayList<Long>());
     272            } else if (qName.equals("nd")) {
     273                Collection<Long> list = ways.get(current.id);
     274                if (list == null) {
     275                    throwException(
     276                            tr("found XML element <nd> element not as direct child of element <way>")
     277                    );
     278                }
     279                if (atts.getValue("ref") == null) {
     280                    throwException(
     281                            tr("Missing mandatory attribute ''{0}'' on <nd> of way {1}", "ref", current.id)
     282                    );
     283                }
     284                long id = getLong(atts, "ref");
     285                if (id == 0) {
     286                    throwException(
     287                            tr("Illegal value of attribute ''ref'' of element <nd>. Got {0}", id)
     288                    );
     289                }
     290                list.add(id);
     291
     292                // ---- PARSING RELATIONS ----
     293
     294            } else if (qName.equals("relation")) {
     295                current = new OsmPrimitiveData();
     296                readCommon(atts, current);
     297                Relation r = current.createRelation();
     298                externalIdMap.put("r"+current.id, r );
     299                relations.put(current.id, new LinkedList<RelationMemberData>());
     300            } else if (qName.equals("member")) {
     301                Collection<RelationMemberData> list = relations.get(current.id);
     302                if (list == null) {
     303                    throwException(
     304                            tr("Found XML element <member> not as direct child of element <relation>")
     305                    );
     306                }
     307                RelationMemberData emd = new RelationMemberData();
     308                String value = atts.getValue("ref");
     309                if (value == null) {
     310                    throwException(tr("Missing attribute ''ref'' on member in relation {0}",current.id));
     311                }
     312                try {
     313                    emd.id = Long.parseLong(value);
     314                } catch(NumberFormatException e) {
     315                    throwException(tr("Illegal value for attribute ''ref'' on member in relation {0}. Got {1}", Long.toString(current.id),value));
     316                }
     317                value = atts.getValue("type");
     318                if (value == null) {
     319                    throwException(tr("Missing attribute ''type'' on member {0} in relation {1}", Long.toString(emd.id), Long.toString(current.id)));
     320                }
     321                if (! (value.equals("way") || value.equals("node") || value.equals("relation"))) {
     322                    throwException(tr("Illegal value for attribute ''type'' on member {0} in relation {1}. Got {2}.", Long.toString(emd.id), Long.toString(current.id), value));
     323                }
     324                emd.type= value;
     325                value = atts.getValue("role");
     326                emd.role = value;
     327
     328                if (emd.id == 0) {
     329                    throwException(tr("Incomplete <member> specification with ref=0"));
     330                }
     331
     332                list.add(emd);
     333
     334                // ---- PARSING TAGS (applicable to all objects) ----
     335
     336            } else if (qName.equals("tag")) {
     337                String key = atts.getValue("k");
     338                String value = atts.getValue("v");
     339                current.rememberTag(key, value);
    248340            }
    249341        }
     
    252344            return Double.parseDouble(atts.getValue(value));
    253345        }
    254     }
    255 
    256     /**
    257      * Read out the common attributes from atts and put them into this.current.
    258      */
    259     void readCommon(Attributes atts, OsmPrimitiveData current) throws SAXException {
    260         current.id = getLong(atts, "id");
    261         if (current.id == 0)
    262             throw new SAXException(tr("Illegal object with id=0"));
    263 
    264         String time = atts.getValue("timestamp");
    265         if (time != null && time.length() != 0) {
    266             current.timestamp =  DateUtils.fromString(time);
    267         }
    268 
    269         // user attribute added in 0.4 API
    270         String user = atts.getValue("user");
    271         if (user != null) {
    272             // do not store literally; get object reference for string
    273             current.user = User.get(user);
    274         }
    275 
    276         // uid attribute added in 0.6 API
    277         String uid = atts.getValue("uid");
    278         if (uid != null) {
    279             if (current.user != null) {
    280                 current.user.uid = uid;
    281             }
    282         }
    283 
    284         // visible attribute added in 0.4 API
    285         String visible = atts.getValue("visible");
    286         if (visible != null) {
    287             current.visible = Boolean.parseBoolean(visible);
    288         }
    289 
    290         String version = atts.getValue("version");
    291         current.version = 0;
    292         if (version != null) {
     346
     347        private User createUser(String uid, String name) throws SAXException {
     348            if (uid == null) {
     349                if (name == null)
     350                    return null;
     351                return User.createLocalUser(name);
     352            }
    293353            try {
    294                 current.version = Integer.parseInt(version);
     354                long id = Long.parseLong(uid);
     355                return User.createOsmUser(id, name);
    295356            } catch(NumberFormatException e) {
    296                 throw new SAXException(tr("Illegal value for attribute \"version\" on OSM primitive with id {0}, got {1}", Long.toString(current.id), version));
    297             }
    298         } else {
    299             // version expected for OSM primitives with an id assigned by the server (id > 0), since API 0.6
    300             //
    301             if (current.id > 0 && ds.version != null && ds.version.equals("0.6"))
    302                 throw new SAXException(tr("Missing attribute \"version\" on OSM primitive with id {0}", Long.toString(current.id)));
    303         }
    304 
    305         String action = atts.getValue("action");
    306         if (action == null)
    307             return;
    308         if (action.equals("delete")) {
    309             current.deleted = true;
    310         } else if (action.startsWith("modify")) {
    311             current.modified = true;
    312         }
    313     }
    314     private long getLong(Attributes atts, String value) throws SAXException {
    315         String s = atts.getValue(value);
    316         if (s == null)
    317             throw new SAXException(tr("Missing required attribute \"{0}\".",value));
    318         return Long.parseLong(s);
    319     }
    320 
    321     private Node findNode(long id) {
    322         Node n = nodes.get(id);
    323         if (n != null)
    324             return n;
    325         return null;
    326     }
    327 
    328     protected void createWays() {
    329         for (Entry<OsmPrimitiveData, Collection<Long>> e : ways.entrySet()) {
    330             Way w = new Way(e.getKey().id);
     357                throwException(tr("Illegal value for attribute ''uid''. Got ''{0}''", uid));
     358            }
     359            return null;
     360        }
     361        /**
     362         * Read out the common attributes from atts and put them into this.current.
     363         */
     364        void readCommon(Attributes atts, OsmPrimitiveData current) throws SAXException {
     365            current.id = getLong(atts, "id");
     366            if (current.id == 0) {
     367                throwException(tr("Illegal object with id=0"));
     368            }
     369
     370            String time = atts.getValue("timestamp");
     371            if (time != null && time.length() != 0) {
     372                current.timestamp =  DateUtils.fromString(time);
     373            }
     374
     375            // user attribute added in 0.4 API
     376            String user = atts.getValue("user");
     377            // uid attribute added in 0.6 API
     378            String uid = atts.getValue("uid");
     379            current.user = createUser(uid, user);
     380
     381            // visible attribute added in 0.4 API
     382            String visible = atts.getValue("visible");
     383            if (visible != null) {
     384                current.visible = Boolean.parseBoolean(visible);
     385            }
     386
     387            String version = atts.getValue("version");
     388            current.version = 0;
     389            if (version != null) {
     390                try {
     391                    current.version = Integer.parseInt(version);
     392                } catch(NumberFormatException e) {
     393                    throwException(tr("Illegal value for attribute ''version'' on OSM primitive with id {0}. Got {1}", Long.toString(current.id), version));
     394                }
     395                if (current.version <= 0) {
     396                    throwException(tr("Illegal value for attribute ''version'' on OSM primitive with id {0}. Got {1}", Long.toString(current.id), version));
     397                }
     398            } else {
     399                // version expected for OSM primitives with an id assigned by the server (id > 0), since API 0.6
     400                //
     401                if (current.id > 0 && ds.version != null && ds.version.equals("0.6")) {
     402                    throwException(tr("Missing attribute ''version'' on OSM primitive with id {0}", Long.toString(current.id)));
     403                }
     404            }
     405
     406            String action = atts.getValue("action");
     407            if (action == null)
     408                return;
     409            if (action.equals("delete")) {
     410                current.deleted = true;
     411            } else if (action.startsWith("modify")) {
     412                current.modified = true;
     413            }
     414        }
     415
     416        private long getLong(Attributes atts, String name) throws SAXException {
     417            String value = atts.getValue(name);
     418            if (value == null) {
     419                throwException(tr("Missing required attribute ''{0}''.",name));
     420            }
     421            try {
     422                return Long.parseLong(value);
     423            } catch(NumberFormatException e) {
     424                throwException(tr("Illegal long value for attribute ''{0}''. Got ''{1}''",name, value));
     425            }
     426            return 0; // should not happen
     427        }
     428    }
     429
     430
     431    /**
     432     * Processes the ways after parsing. Rebuilds the list of nodes of each way and
     433     * adds the way to the dataset
     434     *
     435     * @throws IllegalDataException thrown if a data integrity problem is detected
     436     */
     437    protected void processWaysAfterParsing() throws IllegalDataException{
     438        for (Long externalWayId: ways.keySet()) {
     439            Way w = (Way)externalIdMap.get("w" + externalWayId);
    331440            boolean incomplete = false;
    332441            List<Node> wayNodes = new ArrayList<Node>();
    333             for (long id : e.getValue()) {
    334                 Node n = findNode(id);
     442            for (long id : ways.get(externalWayId)) {
     443                Node n = (Node)externalIdMap.get("n" +id);
    335444                if (n == null) {
     445                    if (id <= 0)
     446                        throw new IllegalDataException (
     447                                tr(
     448                                        "way with external id ''{0}'' includes missing node with external id ''{1}''",
     449                                        externalWayId,
     450                                        id
     451                                )
     452                        );
    336453                    n = new Node(id);
    337454                    n.incomplete = true;
     
    343460            if (incomplete) {
    344461                logger.warning(tr("marked way {0} with {1} nodes incomplete because at least one node was missing in the " +
    345                                 "loaded data and is therefore incomplete too", e.getKey().id, w.getNodesCount()));
    346                 e.getKey().copyTo(w);
     462                        "loaded data and is therefore incomplete too", externalWayId, w.getNodesCount()));
    347463                w.incomplete = true;
    348464                ds.addPrimitive(w);
    349465            } else {
    350                 e.getKey().copyTo(w);
    351466                w.incomplete = false;
    352467                ds.addPrimitive(w);
     
    356471
    357472    /**
    358      * Return the Way object with the given id, or null if it doesn't
    359      * exist yet. This method only looks at ways stored in the already parsed
    360      * ways.
    361      *
    362      * @param id
    363      * @return way object or null
    364      */
    365     private Way findWay(long id) {
    366         for (Way way : ds.ways)
    367             if (way.id == id)
    368                 return way;
    369         return null;
    370     }
    371 
    372     /**
    373      * Return the Relation object with the given id, or null if it doesn't
    374      * exist yet. This method only looks at relations in the already parsed
    375      * relations.
    376      *
    377      * @param id
    378      * @return relation object or null
    379      */
    380     private Relation findRelation(long id) {
    381         for (Relation e : ds.relations)
    382             if (e.id == id)
    383                 return e;
    384         return null;
    385     }
    386 
    387     /**
    388      * Create relations. This is slightly different than n/s/w because
    389      * unlike other objects, relations may reference other relations; it
    390      * is not guaranteed that a referenced relation will have been created
    391      * before it is referenced. So we have to create all relations first,
    392      * and populate them later.
    393      */
    394     private void createRelations() throws SAXException {
    395 
    396         // pass 1 - create all relations
    397         for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) {
    398             Relation en = new Relation();
    399             e.getKey().copyTo(en);
    400             ds.addPrimitive(en);
    401         }
    402 
    403         // Cache the ways here for much better search performance
    404         HashMap<Long, Way> hm = new HashMap<Long, Way>(10000);
    405         for (Way wy : ds.ways) {
    406             hm.put(wy.id, wy);
    407         }
    408 
    409         // pass 2 - sort out members
    410         for (Entry<OsmPrimitiveData, Collection<RelationMemberData>> e : relations.entrySet()) {
    411             Relation en = findRelation(e.getKey().id);
    412             if (en == null) throw new Error("Failed to create relation " + e.getKey().id);
    413 
     473     * Processes the parsed nodes after parsing. Just adds them to
     474     * the dataset
     475     *
     476     */
     477    protected void processNodesAfterParsing() {
     478        for (OsmPrimitive primitive: externalIdMap.values()) {
     479            if (primitive instanceof Node) {
     480                this.ds.addPrimitive(primitive);
     481            }
     482        }
     483    }
     484
     485    /**
     486     * Completes the parsed relations with its members.
     487     *
     488     * @throws IllegalDataException thrown if a data integrity problem is detected, i.e. if a
     489     * relation member refers to a local primitive which wasn't available in the data
     490     *
     491     */
     492    private void processRelationsAfterParsing() throws IllegalDataException {
     493        for (Long externalRelationId : relations.keySet()) {
     494            Relation relation = (Relation) externalIdMap.get("r" +externalRelationId);
    414495            List<RelationMember> relationMembers = new ArrayList<RelationMember>();
    415 
    416             for (RelationMemberData emd : e.getValue()) {
    417                 OsmPrimitive member;
    418                 if (emd.type.equals("node")) {
    419                     member = findNode(emd.id);
    420                     if (member == null) {
    421                         member = new Node(emd.id);
    422                         ds.addPrimitive(member);
     496            for (RelationMemberData rm : relations.get(externalRelationId)) {
     497                OsmPrimitive primitive = null;
     498
     499                // lookup the member from the map of already created primitives
     500                //
     501                if (rm.type.equals("node")) {
     502                    primitive = externalIdMap.get("n" + rm.id);
     503                } else if (rm.type.equals("way")) {
     504                    primitive = externalIdMap.get("w" + rm.id);
     505                } else if (rm.type.equals("relation")) {
     506                    primitive = externalIdMap.get("r" + rm.id);
     507                } else
     508                    throw new IllegalDataException(
     509                            tr("Unknown relation member type ''{0}'' in relation with external id ''{1}''", rm.type,externalRelationId)
     510                    );
     511
     512                if (primitive == null) {
     513                    if (rm.id <= 0)
     514                        // relation member refers to a primitive with a negative id which was not
     515                        // found in the data. This is always a data integrity problem and we abort
     516                        // with an exception
     517                        //
     518                        throw new IllegalDataException(
     519                                tr(
     520                                        "Relation with external id ''{0}'' refers to missing primitive with external id ''{1}''",
     521                                        externalRelationId,
     522                                        rm.id
     523                                )
     524                        );
     525
     526                    // member refers to OSM primitive which was not present in the parsed data
     527                    // -> create a new incomplete primitive and add it to the dataset
     528                    //
     529                    if (rm.type.equals("node")) {
     530                        primitive = new Node(rm.id);
     531                    } else if (rm.type.equals("way")) {
     532                        primitive = new Way(rm.id);
     533                    } else if (rm.type.equals("relation")) {
     534                        primitive = new Relation(rm.id);
     535                    } else {
     536                        // can't happen, we've been testing for valid member types
     537                        // at the beginning of this method
     538                        //
    423539                    }
    424                 } else if (emd.type.equals("way")) {
    425                     member = hm.get(emd.id);
    426                     if (member == null) {
    427                         member = findWay(emd.id);
    428                     }
    429                     if (member == null) {
    430                         member = new Way(emd.id);
    431                         ds.addPrimitive(member);
    432                     }
    433                 } else if (emd.type.equals("relation")) {
    434                     member = findRelation(emd.id);
    435                     if (member == null) {
    436                         member = new Relation(emd.id);
    437                         ds.addPrimitive(member);
    438                     }
    439                 } else {
    440                     throw new SAXException(tr("Unknown relation member type {0}", emd.type));
    441                 }
    442                 relationMembers.add(new RelationMember(emd.role, member));
    443             }
    444             en.setMembers(relationMembers);
    445         }
    446         hm = null;
     540                    ds.addPrimitive(primitive);
     541                }
     542                relationMembers.add(new RelationMember(rm.role, primitive));
     543            }
     544            relation.setMembers(relationMembers);
     545            ds.addPrimitive(relation);
     546        }
    447547    }
    448548
    449549    /**
    450550     * Parse the given input source and return the dataset.
    451      * @param ref The dataset that is search in for references first. If
    452      *      the Reference is not found here, Main.ds is searched and a copy of the
    453      *  element found there is returned.
    454      */
    455     public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws SAXException, IOException {
    456         return parseDataSetOsm(source, progressMonitor).ds;
    457     }
    458 
    459     public static OsmReader parseDataSetOsm(InputStream source, ProgressMonitor progressMonitor) throws SAXException, IOException {
     551     *
     552     * @param source the source input stream
     553     * @param progressMonitor  the progress monitor
     554     *
     555     * @return the dataset with the parsed data
     556     * @throws IllegalDataException thrown if the an error was found while parsing the data from the source
     557     */
     558    public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
    460559        OsmReader reader = new OsmReader();
    461 
    462         // phase 1: Parse nodes and read in raw ways
    463         InputSource inputSource = new InputSource(new InputStreamReader(source, "UTF-8"));
    464560        try {
     561            progressMonitor.beginTask(tr("Prepare OSM data...", 2));
     562            progressMonitor.subTask(tr("Parsing OSM data..."));
     563            InputSource inputSource = new InputSource(new InputStreamReader(source, "UTF-8"));
    465564            SAXParserFactory.newInstance().newSAXParser().parse(inputSource, reader.new Parser());
    466         } catch (ParserConfigurationException e1) {
    467             e1.printStackTrace(); // broken SAXException chaining
    468             throw new SAXException(e1);
    469         }
    470 
    471         progressMonitor.beginTask(tr("Prepare OSM data...", 2));
    472         try {
    473             for (Node n : reader.nodes.values()) {
    474                 reader.ds.addPrimitive(n);
    475             }
    476 
    477565            progressMonitor.worked(1);
    478566
    479             try {
    480                 reader.createWays();
    481                 reader.createRelations();
    482             } catch (NumberFormatException e) {
    483                 e.printStackTrace();
    484                 throw new SAXException(tr("Ill-formed node id"));
    485             }
    486 
    487             // clear all negative ids (new to this file)
    488             for (OsmPrimitive o : reader.ds.allPrimitives())
    489                 if (o.id < 0) {
    490                     o.id = 0;
    491                 }
    492 
    493             return reader;
     567            progressMonitor.subTask(tr("Preparing data set..."));
     568            reader.processNodesAfterParsing();
     569            reader.processWaysAfterParsing();
     570            reader.processRelationsAfterParsing();
     571            progressMonitor.worked(1);
     572            return reader.getDataSet();
     573        } catch(IllegalDataException e) {
     574            throw e;
     575        } catch(ParserConfigurationException e) {
     576            throw new IllegalDataException(e.getMessage(), e);
     577        } catch(SAXException e) {
     578            throw new IllegalDataException(e.getMessage(), e);
     579        } catch(Exception e) {
     580            throw new IllegalDataException(e);
    494581        } finally {
    495582            progressMonitor.finishTask();
  • trunk/src/org/openstreetmap/josm/io/OsmServerBackreferenceReader.java

    r1811 r2070  
    5151        if (primitive == null)
    5252            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "primitive"));
    53         if (primitive.id == 0)
    54             throw new IllegalArgumentException(tr("id parameter ''{0}'' > 0 required. Got {1}", "primitive", primitive.id));
    55         this.id = primitive.id;
     53        if (primitive.getId() == 0)
     54            throw new IllegalArgumentException(tr("id parameter ''{0}'' > 0 required. Got {1}", "primitive", primitive.getId()));
     55        this.id = primitive.getId();
    5656        this.primitiveType = OsmPrimitiveType.from(primitive);
    5757        this.readFull = false;
     
    222222            if (isReadFull() ||primitiveType.equals(OsmPrimitiveType.NODE)) {
    223223                for (Way way: waysToCheck) {
    224                     if (way.id > 0 && way.incomplete) {
    225                         OsmServerObjectReader reader = new OsmServerObjectReader(way.id, OsmPrimitiveType.from(way), true /* read full */);
     224                    if (way.getId() > 0 && way.incomplete) {
     225                        OsmServerObjectReader reader = new OsmServerObjectReader(way.getId(), OsmPrimitiveType.from(way), true /* read full */);
    226226                        DataSet wayDs = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
    227227                        MergeVisitor visitor = new MergeVisitor(ds, wayDs);
     
    233233                Collection<Relation> relationsToCheck  = new ArrayList<Relation>(ds.relations);
    234234                for (Relation relation: relationsToCheck) {
    235                     if (relation.id > 0 && relation.incomplete) {
    236                         OsmServerObjectReader reader = new OsmServerObjectReader(relation.id, OsmPrimitiveType.from(relation), true /* read full */);
     235                    if (relation.getId() > 0 && relation.incomplete) {
     236                        OsmServerObjectReader reader = new OsmServerObjectReader(relation.getId(), OsmPrimitiveType.from(relation), true /* read full */);
    237237                        DataSet wayDs = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
    238238                        MergeVisitor visitor = new MergeVisitor(ds, wayDs);
  • trunk/src/org/openstreetmap/josm/io/OsmServerObjectReader.java

    r1827 r2070  
    4646            if (in == null)
    4747                return null;
    48             final OsmReader osm = OsmReader.parseDataSetOsm(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    49             final DataSet data = osm.getDs();
     48            final DataSet data = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
    5049            return data;
    5150        } catch(OsmTransferException e) {
  • trunk/src/org/openstreetmap/josm/io/OsmWriter.java

    r2025 r2070  
    1414import org.openstreetmap.josm.data.osm.Relation;
    1515import org.openstreetmap.josm.data.osm.RelationMember;
     16import org.openstreetmap.josm.data.osm.User;
    1617import org.openstreetmap.josm.data.osm.Way;
    1718import org.openstreetmap.josm.data.osm.visitor.Visitor;
     
    208209        // user and visible added with 0.4 API
    209210        if (osm.user != null) {
    210             out.print(" user='"+XmlWriter.encode(osm.user.name)+"'");
     211            if(osm.user.isLocalUser()) {
     212                out.print(" user='"+XmlWriter.encode(osm.user.getName())+"'");
     213            } else if (osm.user.isOsmUser()) {
     214                // uid added with 0.6
     215                out.print(" uid='"+ osm.user.getId()+"'");
     216                out.print(" user='"+XmlWriter.encode(osm.user.getName())+"'");
     217            }
    211218        }
    212219        out.print(" visible='"+osm.isVisible()+"'");
    213         if (osm.version != -1) {
    214             out.print(" version='"+osm.version+"'");
     220        if (osm.getVersion() != 0) {
     221            out.print(" version='"+osm.getVersion()+"'");
    215222        }
    216223        if (this.changeset != null && this.changeset.getId() != 0) {
Note: See TracChangeset for help on using the changeset viewer.