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