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