001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.io.File;
007import java.io.FileNotFoundException;
008import java.io.IOException;
009import java.io.OutputStream;
010import java.io.OutputStreamWriter;
011import java.io.PrintWriter;
012import java.io.Writer;
013import java.nio.charset.StandardCharsets;
014import java.text.MessageFormat;
015
016import javax.swing.JOptionPane;
017
018import org.openstreetmap.josm.Main;
019import org.openstreetmap.josm.actions.ExtensionFileFilter;
020import org.openstreetmap.josm.gui.layer.Layer;
021import org.openstreetmap.josm.gui.layer.OsmDataLayer;
022import org.openstreetmap.josm.tools.Utils;
023
024public class OsmExporter extends FileExporter {
025
026    /**
027     * Constructs a new {@code OsmExporter}.
028     */
029    public OsmExporter() {
030        super(OsmImporter.FILE_FILTER);
031    }
032
033    public OsmExporter(ExtensionFileFilter filter) {
034        super(filter);
035    }
036
037    @Override
038    public boolean acceptFile(File pathname, Layer layer) {
039        if (!(layer instanceof OsmDataLayer))
040            return false;
041        return super.acceptFile(pathname, layer);
042    }
043
044    @Override
045    public void exportData(File file, Layer layer) throws IOException {
046        exportData(file, layer, false);
047    }
048
049    public void exportData(File file, Layer layer, boolean noBackup) throws IllegalArgumentException {
050        if (layer instanceof OsmDataLayer) {
051            save(file, (OsmDataLayer) layer, noBackup);
052        } else
053            throw new IllegalArgumentException(MessageFormat.format("Expected instance of OsmDataLayer. Got ''{0}''.", layer
054                    .getClass().getName()));
055    }
056
057    protected OutputStream getOutputStream(File file) throws FileNotFoundException, IOException {
058        return Compression.getCompressedFileOutputStream(file);
059    }
060
061    private void save(File file, OsmDataLayer layer, boolean noBackup) {
062        File tmpFile = null;
063        try {
064            // use a tmp file because if something errors out in the
065            // process of writing the file, we might just end up with
066            // a truncated file.  That can destroy lots of work.
067            if (file.exists()) {
068                tmpFile = new File(file.getPath() + "~");
069                Utils.copyFile(file, tmpFile);
070            }
071
072            // create outputstream and wrap it with gzip or bzip, if necessary
073            try (
074                OutputStream out = getOutputStream(file);
075                Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
076                OsmWriter w = OsmWriterFactory.createOsmWriter(new PrintWriter(writer), false, layer.data.getVersion());
077            ) {
078                layer.data.getReadLock().lock();
079                try {
080                    w.writeLayer(layer);
081                } finally {
082                    layer.data.getReadLock().unlock();
083                }
084            }
085            if (noBackup || !Main.pref.getBoolean("save.keepbackup", false)) {
086                if (tmpFile != null) {
087                    tmpFile.delete();
088                }
089            }
090            layer.onPostSaveToFile();
091        } catch (IOException e) {
092            Main.error(e);
093            JOptionPane.showMessageDialog(
094                    Main.parent,
095                    tr("<html>An error occurred while saving.<br>Error is:<br>{0}</html>", e.getMessage()),
096                    tr("Error"),
097                    JOptionPane.ERROR_MESSAGE
098            );
099
100            try {
101                // if the file save failed, then the tempfile will not
102                // be deleted.  So, restore the backup if we made one.
103                if (tmpFile != null && tmpFile.exists()) {
104                    Utils.copyFile(tmpFile, file);
105                }
106            } catch (IOException e2) {
107                Main.error(e2);
108                JOptionPane.showMessageDialog(
109                        Main.parent,
110                        tr("<html>An error occurred while restoring backup file.<br>Error is:<br>{0}</html>", e2.getMessage()),
111                        tr("Error"),
112                        JOptionPane.ERROR_MESSAGE
113                );
114            }
115        }
116    }
117}