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.Way;
015import org.openstreetmap.josm.gui.ExceptionDialogUtil;
016import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
017import org.openstreetmap.josm.io.OnlineResource;
018import org.openstreetmap.josm.io.OsmApi;
019import org.openstreetmap.josm.io.OsmApiInitializationException;
020import org.openstreetmap.josm.io.OsmTransferCanceledException;
021
022public class ApiPreconditionCheckerHook implements UploadHook {
023
024    @Override
025    public boolean checkUpload(APIDataSet apiData) {
026        OsmApi api = OsmApi.getOsmApi();
027        try {
028            if (Main.isOffline(OnlineResource.OSM_API)) {
029                return false;
030            }
031            // FIXME: this should run asynchronously and a progress monitor
032            // should be displayed.
033            api.initialize(NullProgressMonitor.INSTANCE);
034            long maxNodes = api.getCapabilities().getMaxWayNodes();
035            if (maxNodes > 0) {
036                if (!checkMaxNodes(apiData.getPrimitivesToAdd(), maxNodes))
037                    return false;
038                if (!checkMaxNodes(apiData.getPrimitivesToUpdate(), maxNodes))
039                    return false;
040                if (!checkMaxNodes(apiData.getPrimitivesToDelete(), maxNodes))
041                    return false;
042            }
043        } catch (OsmTransferCanceledException e) {
044            Main.trace(e);
045            return false;
046        } catch (OsmApiInitializationException e) {
047            ExceptionDialogUtil.explainOsmTransferException(e);
048            return false;
049        }
050        return true;
051    }
052
053    private static boolean checkMaxNodes(Collection<OsmPrimitive> primitives, long maxNodes) {
054        for (OsmPrimitive osmPrimitive : primitives) {
055            for (String key: osmPrimitive.keySet()) {
056                String value = osmPrimitive.get(key);
057                if (key.length() > 255) {
058                    if (osmPrimitive.isDeleted()) {
059                        // if OsmPrimitive is going to be deleted we automatically shorten the value
060                        Main.warn(
061                                tr("Automatically truncating value of tag ''{0}'' on deleted object {1}",
062                                        key,
063                                        Long.toString(osmPrimitive.getId())
064                                )
065                        );
066                        osmPrimitive.put(key, value.substring(0, 255));
067                        continue;
068                    }
069                    JOptionPane.showMessageDialog(Main.parent,
070                            tr("Length of value for tag ''{0}'' on object {1} exceeds the max. allowed length {2}. Values length is {3}.",
071                                    key, Long.toString(osmPrimitive.getId()), 255, value.length()
072                            ),
073                            tr("Precondition Violation"),
074                            JOptionPane.ERROR_MESSAGE
075                    );
076                    Main.getLayerManager().getEditDataSet().setSelected(Collections.singleton(osmPrimitive));
077                    return false;
078                }
079            }
080
081            if (osmPrimitive instanceof Way &&
082                    ((Way) osmPrimitive).getNodesCount() > maxNodes) {
083                JOptionPane.showMessageDialog(
084                        Main.parent,
085                        tr("{0} nodes in way {1} exceed the max. allowed number of nodes {2}",
086                                ((Way) osmPrimitive).getNodesCount(),
087                                Long.toString(osmPrimitive.getId()),
088                                maxNodes
089                        ),
090                        tr("API Capabilities Violation"),
091                        JOptionPane.ERROR_MESSAGE
092                );
093                Main.getLayerManager().getEditDataSet().setSelected(Collections.singleton(osmPrimitive));
094                return false;
095            }
096        }
097        return true;
098    }
099}