source: josm/trunk/src/org/openstreetmap/josm/io/AbstractReader.java @ 5241

Revision 5123, 8.3 KB checked in by Don-vip, 2 months ago (diff)

Remove final specifier on AbstractReader.ds to allow implementations to replace it instead of having to call DataSet.mergeFrom() (costly operation)

Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.HashMap;
9import java.util.List;
10import java.util.Map;
11
12import org.openstreetmap.josm.data.osm.Changeset;
13import org.openstreetmap.josm.data.osm.DataSet;
14import org.openstreetmap.josm.data.osm.Node;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
17import org.openstreetmap.josm.data.osm.PrimitiveId;
18import org.openstreetmap.josm.data.osm.Relation;
19import org.openstreetmap.josm.data.osm.RelationMember;
20import org.openstreetmap.josm.data.osm.RelationMemberData;
21import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
22import org.openstreetmap.josm.data.osm.Way;
23
24/**
25 * Abstract Reader, allowing other implementations than OsmReader (PbfReader in PBF plugin for example)
26 * @author Vincent
27 *
28 */
29public abstract class AbstractReader {
30
31    /**
32     * The dataset to add parsed objects to.
33     */
34    protected DataSet ds = new DataSet();
35
36    protected Changeset uploadChangeset;
37
38    /** the map from external ids to read OsmPrimitives. External ids are
39     * longs too, but in contrast to internal ids negative values are used
40     * to identify primitives unknown to the OSM server
41     */
42    protected final Map<PrimitiveId, OsmPrimitive> externalIdMap = new HashMap<PrimitiveId, OsmPrimitive>();
43
44    /**
45     * Data structure for the remaining way objects
46     */
47    protected final Map<Long, Collection<Long>> ways = new HashMap<Long, Collection<Long>>();
48
49    /**
50     * Data structure for relation objects
51     */
52    protected final Map<Long, Collection<RelationMemberData>> relations = new HashMap<Long, Collection<RelationMemberData>>();
53   
54    /**
55     * Replies the parsed data set
56     *
57     * @return the parsed data set
58     */
59    public DataSet getDataSet() {
60        return ds;
61    }
62   
63    /**
64     * Processes the parsed nodes after parsing. Just adds them to
65     * the dataset
66     *
67     */
68    protected void processNodesAfterParsing() {
69        for (OsmPrimitive primitive: externalIdMap.values()) {
70            if (primitive instanceof Node) {
71                this.ds.addPrimitive(primitive);
72            }
73        }
74    }
75
76    /**
77     * Processes the ways after parsing. Rebuilds the list of nodes of each way and
78     * adds the way to the dataset
79     *
80     * @throws IllegalDataException thrown if a data integrity problem is detected
81     */
82    protected void processWaysAfterParsing() throws IllegalDataException{
83        for (Long externalWayId: ways.keySet()) {
84            Way w = (Way)externalIdMap.get(new SimplePrimitiveId(externalWayId, OsmPrimitiveType.WAY));
85            List<Node> wayNodes = new ArrayList<Node>();
86            for (long id : ways.get(externalWayId)) {
87                Node n = (Node)externalIdMap.get(new SimplePrimitiveId(id, OsmPrimitiveType.NODE));
88                if (n == null) {
89                    if (id <= 0)
90                        throw new IllegalDataException (
91                                tr("Way with external ID ''{0}'' includes missing node with external ID ''{1}''.",
92                                        externalWayId,
93                                        id));
94                    // create an incomplete node if necessary
95                    //
96                    n = (Node)ds.getPrimitiveById(id,OsmPrimitiveType.NODE);
97                    if (n == null) {
98                        n = new Node(id);
99                        ds.addPrimitive(n);
100                    }
101                }
102                if (n.isDeleted()) {
103                    System.out.println(tr("Deleted node {0} is part of way {1}", id, w.getId()));
104                } else {
105                    wayNodes.add(n);
106                }
107            }
108            w.setNodes(wayNodes);
109            if (w.hasIncompleteNodes()) {
110                  System.out.println(tr("Way {0} with {1} nodes has incomplete nodes because at least one node was missing in the loaded data.",
111                          externalWayId, w.getNodesCount()));
112            }
113            ds.addPrimitive(w);
114        }
115    }
116
117    /**
118     * Completes the parsed relations with its members.
119     *
120     * @throws IllegalDataException thrown if a data integrity problem is detected, i.e. if a
121     * relation member refers to a local primitive which wasn't available in the data
122     *
123     */
124    protected void processRelationsAfterParsing() throws IllegalDataException {
125
126        // First add all relations to make sure that when relation reference other relation, the referenced will be already in dataset
127        for (Long externalRelationId : relations.keySet()) {
128            Relation relation = (Relation) externalIdMap.get(
129                    new SimplePrimitiveId(externalRelationId, OsmPrimitiveType.RELATION)
130            );
131            ds.addPrimitive(relation);
132        }
133
134        for (Long externalRelationId : relations.keySet()) {
135            Relation relation = (Relation) externalIdMap.get(
136                    new SimplePrimitiveId(externalRelationId, OsmPrimitiveType.RELATION)
137            );
138            List<RelationMember> relationMembers = new ArrayList<RelationMember>();
139            for (RelationMemberData rm : relations.get(externalRelationId)) {
140                OsmPrimitive primitive = null;
141
142                // lookup the member from the map of already created primitives
143                primitive = externalIdMap.get(new SimplePrimitiveId(rm.getMemberId(), rm.getMemberType()));
144
145                if (primitive == null) {
146                    if (rm.getMemberId() <= 0)
147                        // relation member refers to a primitive with a negative id which was not
148                        // found in the data. This is always a data integrity problem and we abort
149                        // with an exception
150                        //
151                        throw new IllegalDataException(
152                                tr("Relation with external id ''{0}'' refers to a missing primitive with external id ''{1}''.",
153                                        externalRelationId,
154                                        rm.getMemberId()));
155
156                    // member refers to OSM primitive which was not present in the parsed data
157                    // -> create a new incomplete primitive and add it to the dataset
158                    //
159                    primitive = ds.getPrimitiveById(rm.getMemberId(), rm.getMemberType());
160                    if (primitive == null) {
161                        switch (rm.getMemberType()) {
162                        case NODE:
163                            primitive = new Node(rm.getMemberId()); break;
164                        case WAY:
165                            primitive = new Way(rm.getMemberId()); break;
166                        case RELATION:
167                            primitive = new Relation(rm.getMemberId()); break;
168                        default: throw new AssertionError(); // can't happen
169                        }
170
171                        ds.addPrimitive(primitive);
172                        externalIdMap.put(new SimplePrimitiveId(rm.getMemberId(), rm.getMemberType()), primitive);
173                    }
174                }
175                if (primitive.isDeleted()) {
176                    System.out.println(tr("Deleted member {0} is used by relation {1}", primitive.getId(), relation.getId()));
177                } else {
178                    relationMembers.add(new RelationMember(rm.getRole(), primitive));
179                }
180            }
181            relation.setMembers(relationMembers);
182        }
183    }
184
185    protected void processChangesetAfterParsing() {
186        if (uploadChangeset != null) {
187            for (Map.Entry<String, String> e : uploadChangeset.getKeys().entrySet()) {
188                ds.addChangeSetTag(e.getKey(), e.getValue());
189            }
190        }
191    }
192   
193    protected final void prepareDataSet() throws IllegalDataException {
194        try {
195            ds.beginUpdate();
196            processNodesAfterParsing();
197            processWaysAfterParsing();
198            processRelationsAfterParsing();
199            processChangesetAfterParsing();
200        } finally {
201            ds.endUpdate();
202        }
203    }
204}
Note: See TracBrowser for help on using the repository browser.