source: josm/trunk/src/org/openstreetmap/josm/actions/upload/FixDataHook.java

Last change on this file was 11913, checked in by Don-vip, 6 weeks ago

sonar - squid:S1192 - String literals should not be duplicated

  • Property svn:eol-style set to native
File size: 7.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.upload;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.Collection;
7import java.util.Collections;
8import java.util.HashMap;
9import java.util.LinkedList;
10import java.util.List;
11import java.util.Map;
12import java.util.Map.Entry;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.command.ChangePropertyCommand;
16import org.openstreetmap.josm.command.Command;
17import org.openstreetmap.josm.command.SequenceCommand;
18import org.openstreetmap.josm.data.APIDataSet;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.Relation;
21import org.openstreetmap.josm.data.osm.Tag;
22
23/**
24 * Fixes defective data entries for all modified objects before upload
25 * @since 5621
26 */
27public class FixDataHook implements UploadHook {
28
29    private static final String ONEWAY = "oneway";
30
31    /**
32     * List of checks to run on data
33     */
34    private final List<FixData> deprecated = new LinkedList<>();
35
36    /**
37     * Constructor for data initialization
38     */
39    public FixDataHook() {
40        // CHECKSTYLE.OFF: SingleSpaceSeparator
41        deprecated.add(new FixDataSpace());
42        deprecated.add(new FixDataKey("color",            "colour"));
43        deprecated.add(new FixDataTag("highway", "ford",  "ford",    "yes"));
44        deprecated.add(new FixDataTag(ONEWAY,    "false",  ONEWAY,   "no"));
45        deprecated.add(new FixDataTag(ONEWAY,    "0",      ONEWAY,   "no"));
46        deprecated.add(new FixDataTag(ONEWAY,    "true",   ONEWAY,   "yes"));
47        deprecated.add(new FixDataTag(ONEWAY,    "1",      ONEWAY,   "yes"));
48        deprecated.add(new FixDataTag("highway", "stile", "barrier", "stile"));
49        // CHECKSTYLE.ON: SingleSpaceSeparator
50        deprecated.add((keys, osm) -> {
51            if (osm instanceof Relation && "multipolygon".equals(keys.get("type")) && "administrative".equals(keys.get("boundary"))) {
52                keys.put("type", "boundary");
53                return true;
54            }
55            return false;
56        });
57    }
58
59    /**
60     * Common set of commands for data fixing
61     * @since 10600 (functional interface)
62     */
63    @FunctionalInterface
64    public interface FixData {
65        /**
66         * Checks if data needs to be fixed and change keys
67         *
68         * @param keys list of keys to be modified
69         * @param osm the object for type validation, don't use keys of it!
70         * @return <code>true</code> if keys have been modified
71         */
72        boolean fixKeys(Map<String, String> keys, OsmPrimitive osm);
73    }
74
75    /**
76     * Data fix to remove spaces at begin or end of tags
77     */
78    public static class FixDataSpace implements FixData {
79        @Override
80        public boolean fixKeys(Map<String, String> keys, OsmPrimitive osm) {
81            Map<String, String> newKeys = new HashMap<>(keys);
82            for (Entry<String, String> e : keys.entrySet()) {
83                String v = Tag.removeWhiteSpaces(e.getValue());
84                String k = Tag.removeWhiteSpaces(e.getKey());
85                boolean drop = k.isEmpty() || v.isEmpty();
86                if (!e.getKey().equals(k)) {
87                    if (drop || !keys.containsKey(k)) {
88                        newKeys.put(e.getKey(), null);
89                        if (!drop)
90                            newKeys.put(k, v);
91                    }
92                } else if (!e.getValue().equals(v)) {
93                    newKeys.put(k, v.isEmpty() ? null : v);
94                } else if (drop) {
95                    newKeys.put(e.getKey(), null);
96                }
97            }
98            boolean changed = !keys.equals(newKeys);
99            if (changed) {
100                keys.clear();
101                keys.putAll(newKeys);
102            }
103            return changed;
104        }
105    }
106
107    /**
108     * Data fix to cleanup wrong spelled keys
109     */
110    public static class FixDataKey implements FixData {
111        /** key of wrong data */
112        private final String oldKey;
113        /** key of correct data */
114        private final String newKey;
115
116        /**
117         * Setup key check for wrong spelled keys
118         *
119         * @param oldKey wrong spelled key
120         * @param newKey correct replacement
121         */
122        public FixDataKey(String oldKey, String newKey) {
123            this.oldKey = oldKey;
124            this.newKey = newKey;
125        }
126
127        @Override
128        public boolean fixKeys(Map<String, String> keys, OsmPrimitive osm) {
129            if (keys.containsKey(oldKey) && !keys.containsKey(newKey)) {
130                keys.put(newKey, keys.get(oldKey));
131                keys.put(oldKey, null);
132                return true;
133            } else if (keys.containsKey(oldKey) && keys.containsKey(newKey) && keys.get(oldKey).equals(keys.get(newKey))) {
134                keys.put(oldKey, null);
135                return true;
136            }
137            return false;
138        }
139    }
140
141    /**
142     * Data fix to cleanup wrong spelled tags
143     */
144    public static class FixDataTag implements FixData {
145        /** key of wrong data */
146        private final String oldKey;
147        /** value of wrong data */
148        private final String oldValue;
149        /** key of correct data */
150        private final String newKey;
151        /** value of correct data */
152        private final String newValue;
153
154        /**
155         * Setup key check for wrong spelled keys
156         *
157         * @param oldKey wrong or old key
158         * @param oldValue wrong or old value
159         * @param newKey correct key replacement
160         * @param newValue correct value replacement
161         */
162        public FixDataTag(String oldKey, String oldValue, String newKey, String newValue) {
163            this.oldKey = oldKey;
164            this.oldValue = oldValue;
165            this.newKey = newKey;
166            this.newValue = newValue;
167        }
168
169        @Override
170        public boolean fixKeys(Map<String, String> keys, OsmPrimitive osm) {
171            if (oldValue.equals(keys.get(oldKey)) && (newKey.equals(oldKey)
172            || !keys.containsKey(newKey) || keys.get(newKey).equals(newValue))) {
173                keys.put(newKey, newValue);
174                if (!newKey.equals(oldKey))
175                    keys.put(oldKey, null);
176                return true;
177            }
178            return false;
179        }
180    }
181
182    /**
183     * Checks the upload for deprecated or wrong tags.
184     * @param apiDataSet the data to upload
185     */
186    @Override
187    public boolean checkUpload(APIDataSet apiDataSet) {
188        if (!Main.pref.getBoolean("fix.data.on.upload", true))
189            return true;
190
191        List<OsmPrimitive> objectsToUpload = apiDataSet.getPrimitives();
192        Collection<Command> cmds = new LinkedList<>();
193
194        for (OsmPrimitive osm : objectsToUpload) {
195            Map<String, String> keys = new HashMap<>(osm.getKeys());
196            if (!keys.isEmpty()) {
197                boolean modified = false;
198                for (FixData fix : deprecated) {
199                    if (fix.fixKeys(keys, osm))
200                        modified = true;
201                }
202                if (modified)
203                    cmds.add(new ChangePropertyCommand(Collections.singleton(osm), keys));
204            }
205        }
206
207        if (!cmds.isEmpty())
208            Main.main.undoRedo.add(new SequenceCommand(tr("Fix deprecated tags"), cmds));
209        return true;
210    }
211}
Note: See TracBrowser for help on using the repository browser.