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