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            return false;
045        } catch (OsmApiInitializationException e) {
046            ExceptionDialogUtil.explainOsmTransferException(e);
047            return false;
048        }
049        return true;
050    }
051
052    private boolean checkMaxNodes(Collection<OsmPrimitive> primitives, long maxNodes) {
053        for (OsmPrimitive osmPrimitive : primitives) {
054            for (String key: osmPrimitive.keySet()) {
055                String value = osmPrimitive.get(key);
056                if (key.length() > 255) {
057                    if (osmPrimitive.isDeleted()) {
058                        // if OsmPrimitive is going to be deleted we automatically shorten the value
059                        Main.warn(
060                                tr("Automatically truncating value of tag ''{0}'' on deleted object {1}",
061                                        key,
062                                        Long.toString(osmPrimitive.getId())
063                                )
064                        );
065                        osmPrimitive.put(key, value.substring(0, 255));
066                        continue;
067                    }
068                    JOptionPane.showMessageDialog(Main.parent,
069                            tr("Length of value for tag ''{0}'' on object {1} exceeds the max. allowed length {2}. Values length is {3}.",
070                                    key, Long.toString(osmPrimitive.getId()), 255, value.length()
071                            ),
072                            tr("Precondition Violation"),
073                            JOptionPane.ERROR_MESSAGE
074                    );
075                    Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
076                    return false;
077                }
078            }
079
080            if (osmPrimitive instanceof Way &&
081                    ((Way)osmPrimitive).getNodesCount() > maxNodes) {
082                JOptionPane.showMessageDialog(
083                        Main.parent,
084                        tr("{0} nodes in way {1} exceed the max. allowed number of nodes {2}",
085                                ((Way)osmPrimitive).getNodesCount(),
086                                Long.toString(osmPrimitive.getId()),
087                                maxNodes
088                        ),
089                        tr("API Capabilities Violation"),
090                        JOptionPane.ERROR_MESSAGE
091                );
092                Main.main.getCurrentDataSet().setSelected(Collections.singleton(osmPrimitive));
093                return false;
094            }
095        }
096        return true;
097    }
098}