001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions.upload;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.util.Collection;
007import java.util.Collections;
008
009import javax.swing.JOptionPane;
010
011import org.openstreetmap.josm.Main;
012import org.openstreetmap.josm.data.APIDataSet;
013import org.openstreetmap.josm.data.osm.OsmPrimitive;
014import org.openstreetmap.josm.data.osm.Tagged;
015import org.openstreetmap.josm.data.osm.Way;
016import org.openstreetmap.josm.gui.ExceptionDialogUtil;
017import org.openstreetmap.josm.gui.MainApplication;
018import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
019import org.openstreetmap.josm.io.OnlineResource;
020import org.openstreetmap.josm.io.OsmApi;
021import org.openstreetmap.josm.io.OsmApiInitializationException;
022import org.openstreetmap.josm.io.OsmTransferCanceledException;
023import org.openstreetmap.josm.tools.Logging;
024
025/**
026 * Checks certain basic conditions, that are listed in the OSM API
027 * {@link org.openstreetmap.josm.io.Capabilities}.
028 */
029public class ApiPreconditionCheckerHook implements UploadHook {
030
031    @Override
032    public boolean checkUpload(APIDataSet apiData) {
033        OsmApi api = OsmApi.getOsmApi();
034        try {
035            if (Main.isOffline(OnlineResource.OSM_API)) {
036                return false;
037            }
038            // FIXME: this should run asynchronously and a progress monitor
039            // should be displayed.
040            api.initialize(NullProgressMonitor.INSTANCE);
041            long maxNodes = api.getCapabilities().getMaxWayNodes();
042            if (maxNodes > 0) {
043                if (!checkMaxNodes(apiData.getPrimitivesToAdd(), maxNodes))
044                    return false;
045                if (!checkMaxNodes(apiData.getPrimitivesToUpdate(), maxNodes))
046                    return false;
047                if (!checkMaxNodes(apiData.getPrimitivesToDelete(), maxNodes))
048                    return false;
049            }
050        } catch (OsmTransferCanceledException e) {
051            Logging.trace(e);
052            return false;
053        } catch (OsmApiInitializationException e) {
054            ExceptionDialogUtil.explainOsmTransferException(e);
055            return false;
056        }
057        return true;
058    }
059
060    private static boolean checkMaxNodes(Collection<OsmPrimitive> primitives, long maxNodes) {
061        for (OsmPrimitive osmPrimitive : primitives) {
062            for (String key: osmPrimitive.keySet()) {
063                String value = osmPrimitive.get(key);
064                if (key.length() > Tagged.MAX_TAG_LENGTH) {
065                    if (osmPrimitive.isDeleted()) {
066                        // if OsmPrimitive is going to be deleted we automatically shorten the value
067                        Logging.warn(
068                                tr("Automatically truncating value of tag ''{0}'' on deleted object {1}",
069                                        key,
070                                        Long.toString(osmPrimitive.getId())
071                                )
072                        );
073                        osmPrimitive.put(key, value.substring(0, Tagged.MAX_TAG_LENGTH));
074                        continue;
075                    }
076                    JOptionPane.showMessageDialog(Main.parent,
077                            tr("Length of value for tag ''{0}'' on object {1} exceeds the max. allowed length {2}. Values length is {3}.",
078                                    key, Long.toString(osmPrimitive.getId()), Tagged.MAX_TAG_LENGTH, value.length()
079                            ),
080                            tr("Precondition violation"),
081                            JOptionPane.ERROR_MESSAGE
082                    );
083                    MainApplication.getLayerManager().getEditDataSet().setSelected(Collections.singleton(osmPrimitive));
084                    return false;
085                }
086            }
087
088            if (osmPrimitive instanceof Way &&
089                    ((Way) osmPrimitive).getNodesCount() > maxNodes) {
090                JOptionPane.showMessageDialog(
091                        Main.parent,
092                        tr("{0} nodes in way {1} exceed the max. allowed number of nodes {2}",
093                                ((Way) osmPrimitive).getNodesCount(),
094                                Long.toString(osmPrimitive.getId()),
095                                maxNodes
096                        ),
097                        tr("API Capabilities Violation"),
098                        JOptionPane.ERROR_MESSAGE
099                );
100                MainApplication.getLayerManager().getEditDataSet().setSelected(Collections.singleton(osmPrimitive));
101                return false;
102            }
103        }
104        return true;
105    }
106}