org.alex73.osm.monitors.export.ExportOutput.java Source code

Java tutorial

Introduction

Here is the source code for org.alex73.osm.monitors.export.ExportOutput.java

Source

/**************************************************************************
     
Some tools for OSM.
    
 Copyright (C) 2014 Ale Buoj?yk <alex73mail@gmail.com>
           Home page: http://www.omegat.org/
           Support center: http://groups.yahoo.com/group/OmegaT/
    
 This is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
    
 This software is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
    
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 **************************************************************************/

package org.alex73.osm.monitors.export;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import org.alex73.osm.utils.Env;
import org.alex73.osm.utils.Lat;
import org.alex73.osm.validators.objects.CheckType;
import org.alex73.osmemory.IOsmNode;
import org.alex73.osmemory.IOsmObject;
import org.alex73.osmemory.IOsmObjectID;
import org.alex73.osmemory.IOsmRelation;
import org.alex73.osmemory.IOsmWay;
import org.alex73.osmemory.MemoryStorage;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;

/**
 * ? ?    ? ???.
 */
public class ExportOutput {
    public static final String CHECKSUM_ALGORITHM = "MD5";

    final String typ, rehijon;
    final File file1, file2;
    String path1, path2;
    String oldchecksum;

    List<IOsmObject> queue = new ArrayList<>();

    /**
     *  ExportOutput' ? ?   border+type.
     */
    public static List<ExportOutput> list(List<CheckType> types, Borders borders, Set<String> unusedFiles)
            throws Exception {
        Collection<File> files = FileUtils.listFiles(new File(Env.readProperty("monitoring.gitdir")),
                new String[] { "txt" }, true);

        List<ExportOutput> result = new ArrayList<>();
        for (CheckType t : types) {
            for (Borders.Border b : borders.kraina) {
                ExportOutput o = new ExportOutput(t.getType().getFile(), b.name);
                if (o.file1.exists() || o.file2.exists()) {
                    result.add(o);
                    files.remove(o.file1);
                    files.remove(o.file2);
                }
            }
            for (Borders.Border b : borders.voblasci) {
                ExportOutput o = new ExportOutput(t.getType().getFile(), b.name);
                if (o.file1.exists() || o.file2.exists()) {
                    result.add(o);
                    files.remove(o.file1);
                    files.remove(o.file2);
                }
            }
            for (Borders.Border b : borders.rajony) {
                ExportOutput o = new ExportOutput(t.getType().getFile(), b.name);
                if (o.file1.exists() || o.file2.exists()) {
                    result.add(o);
                    files.remove(o.file1);
                    files.remove(o.file2);
                }
            }
            for (Borders.Border b : borders.miesty) {
                ExportOutput o = new ExportOutput(t.getType().getFile(), b.name);
                if (o.file1.exists() || o.file2.exists()) {
                    result.add(o);
                    files.remove(o.file1);
                    files.remove(o.file2);
                }
            }
        }
        String prefix = new File(Env.readProperty("monitoring.gitdir")).getAbsolutePath().replace('\\', '/') + '/';
        for (File f : files) {
            String fn = f.getAbsolutePath().replace('\\', '/');
            if (!fn.startsWith(prefix)) {
                throw new RuntimeException("Wrong file: " + f);
            }
            unusedFiles.add(fn.substring(prefix.length()));
        }

        return result;
    }

    public ExportOutput(String typ, String rehijon) throws Exception {
        if (rehijon.startsWith("/")) {
            rehijon = rehijon.substring(1);
        }
        if (rehijon.endsWith("/")) {
            rehijon = rehijon.substring(0, rehijon.length() - 1);
        }
        this.typ = typ;
        this.rehijon = rehijon;
        path1 = rehijon.isEmpty() ? "What/" + typ + ".txt" : "What/" + typ + "/" + rehijon + ".txt";
        path2 = rehijon.isEmpty() ? "Where/" + typ + ".txt" : "Where/" + rehijon + "/" + typ + ".txt";
        path1 = Lat.unhac(Lat.lat(path1, false)).replace(' ', '_');
        path2 = Lat.unhac(Lat.lat(path2, false)).replace(' ', '_');
        file1 = new File(Env.readProperty("monitoring.gitdir") + "/" + path1);
        file1.getParentFile().mkdirs();
        file2 = new File(Env.readProperty("monitoring.gitdir") + "/" + path2);
        file2.getParentFile().mkdirs();

        String ck1 = readChecksum(file1);
        String ck2 = readChecksum(file2);
        if (StringUtils.equals(ck1, ck2)) {
            oldchecksum = ck1;
        }
    }

    public String key() {
        return typ + "|" + rehijon;
    }

    public static String key(String typ, String rehijon) {
        if (rehijon.startsWith("/")) {
            rehijon = rehijon.substring(1);
        }
        if (rehijon.endsWith("/")) {
            rehijon = rehijon.substring(0, rehijon.length() - 1);
        }
        return typ + "|" + rehijon;
    }

    /**
     *  1 '.
     */
    public void out(IOsmObject o) {
        queue.add(o);
    }

    public void clear() {
        queue.clear();
    }

    /**
     * ? '. ? ?  changeset.
     */
    public void forgetInQueue(IOsmObjectID objID) {
        int type = objID.getType();
        long id = objID.getId();
        int low = 0;
        int high = queue.size() - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midvaluetype = queue.get(mid).getType();
            long midvalueid = queue.get(mid).getId();

            if (midvaluetype < type) {
                low = mid + 1;
            } else if (midvaluetype > type) {
                high = mid - 1;
            } else if (midvalueid < id) {
                low = mid + 1;
            } else if (midvalueid > id) {
                high = mid - 1;
            } else {
                queue.remove(mid);
                break;
            }
        }
    }

    /**
     *       ???.
     */
    void save(GitClient git, MemoryStorage osm) {
        try {
            if (queue.isEmpty()) {
                if (file1.exists()) {
                    //  
                    file1.delete();
                    git.remove(path1);
                }
                if (file2.exists()) {
                    //  
                    file2.delete();
                    git.remove(path2);
                }
                oldchecksum = null;
            } else {
                byte[] data = export(osm);
                String ck = calcChecksum(data);
                // 
                if (!ck.equals(oldchecksum)) {
                    FileUtils.writeByteArrayToFile(file1, data);
                    git.add(path1);
                    FileUtils.writeByteArrayToFile(file2, data);
                    git.add(path2);
                    oldchecksum = ck;
                }
            }
        } catch (Exception ex) {
            throw new RuntimeException();
        }
    }

    public void finishUpdate() {
        Collections.sort(queue, new Comparator<IOsmObject>() {
            @Override
            public int compare(IOsmObject o1, IOsmObject o2) {
                int r = o1.getType() - o2.getType();
                if (r == 0) {
                    r = Long.compare(o1.getId(), o2.getId());
                }
                return r;
            }
        });
    }

    private static final Charset OUT_CHARSET = Charset.forName("UTF-8");

    /**
     * ? '
     */
    byte[] export(MemoryStorage osm) throws Exception {
        OutputFormatter formatter = new OutputFormatter(osm);

        for (IOsmObject o : queue) {
            formatter.objectName(o);
            formatter.newLine();
            formatter.otherNames(o);
            formatter.otherTags(o);
            switch (o.getType()) {
            case IOsmObject.TYPE_NODE:
                formatter.getGeometry((IOsmNode) o);
                break;
            case IOsmObject.TYPE_WAY:
                formatter.getGeometry((IOsmWay) o);
                break;
            case IOsmObject.TYPE_RELATION:
                formatter.getGeometry((IOsmRelation) o);
                break;
            default:
                throw new RuntimeException();
            }
        }
        return formatter.getOutput().getBytes(OUT_CHARSET);
    }

    public static String readChecksum(File file) throws Exception {
        if (!file.exists()) {
            return null;
        }
        MessageDigest md = MessageDigest.getInstance(CHECKSUM_ALGORITHM);
        try (RandomAccessFile ra = new RandomAccessFile(file, "r")) {
            try (FileChannel fc = ra.getChannel()) {
                MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
                md.update(buffer);
            }
        }
        return str(md);
    }

    public static String calcChecksum(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance(CHECKSUM_ALGORITHM);
        md.update(data);
        return str(md);
    }

    private static String str(MessageDigest md) {
        byte[] digest = md.digest();
        StringBuilder o = new StringBuilder(40);
        for (int i = 0; i < digest.length; i++) {
            o.append(Integer.toHexString((0xFF & digest[i])));
        }
        return o.toString();
    }
}