heigit.ors.routing.RoutingProfilesUpdater.java Source code

Java tutorial

Introduction

Here is the source code for heigit.ors.routing.RoutingProfilesUpdater.java

Source

/*  This file is part of Openrouteservice.
 *
 *  Openrouteservice is free software; you can redistribute it and/or modify it under the terms of the 
 *  GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 
 *  of the License, or (at your option) any later version.
    
 *  This library 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 Lesser General Public License for more details.
    
 *  You should have received a copy of the GNU Lesser General Public License along with this library; 
 *  if not, see <https://www.gnu.org/licenses/>.  
 */
package heigit.ors.routing;

import com.graphhopper.GraphHopper;
import com.graphhopper.storage.StorableProperties;
import com.graphhopper.util.Helper;
import heigit.ors.routing.configuration.RouteProfileConfiguration;
import heigit.ors.routing.configuration.RouteUpdateConfiguration;
import heigit.ors.routing.traffic.RealTrafficDataProvider;
import heigit.ors.util.DebugUtility;
import heigit.ors.util.FileUtility;
import heigit.ors.util.StackTraceUtility;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Logger;

public class RoutingProfilesUpdater {

    public class UpdateTask extends TimerTask {

        private RoutingProfilesUpdater m_updater;

        public UpdateTask(RoutingProfilesUpdater updater) {
            m_updater = updater;
        }

        public void run() {
            m_updater.run();
        }
    }

    private static Logger LOGGER = Logger.getLogger(RoutingProfilesUpdater.class.getName());

    private RouteUpdateConfiguration m_config;
    private RoutingProfilesCollection m_routeProfiles;
    private Timer m_timer;
    private long m_updatePeriod;
    private boolean m_isRunning;
    private String m_updateStatus = null;
    private Date m_nextUpdate;

    public RoutingProfilesUpdater(RouteUpdateConfiguration config, RoutingProfilesCollection profiles) {
        m_config = config;
        m_routeProfiles = profiles;

        if (m_config.DataSource == null || m_config.DataSource.isEmpty())
            throw new IllegalArgumentException("DataSource is null or empty.");
        if (m_config.WorkingDirectory == null || m_config.WorkingDirectory.isEmpty())
            throw new IllegalArgumentException("WorkingDirectory is null or empty.");
    }

    public void start() {
        // parse time of the format: day of the week, time, period
        String strDateTime = m_config.Time;
        String[] splitValues = strDateTime.split(",");
        int dayOfWeek = Integer.valueOf(splitValues[0].trim()) + 1; // Sunday is 1.
        m_updatePeriod = Integer.valueOf(splitValues[2].trim());
        splitValues = splitValues[1].trim().split(":");
        int hours = Integer.valueOf(splitValues[0].trim());
        int minutes = Integer.valueOf(splitValues[1].trim());
        int seconds = Integer.valueOf(splitValues[2].trim());

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
        calendar.set(Calendar.HOUR_OF_DAY, hours);
        calendar.set(Calendar.MINUTE, minutes);
        calendar.set(Calendar.SECOND, seconds);

        Date firstUpdateTime = calendar.getTime();

        TimerTask timerTask = new UpdateTask(this);
        m_timer = new Timer(true);
        m_timer.schedule(timerTask, firstUpdateTime, m_updatePeriod);

        m_nextUpdate = firstUpdateTime;
        LOGGER.info("Profile updater is started and scheduled at " + firstUpdateTime.toString() + ".");
    }

    private void downloadFile(String url, File destination) {
        try {
            URL website = new URL(url);
            ReadableByteChannel rbc = Channels.newChannel(website.openStream());
            FileOutputStream fos = new FileOutputStream(destination);
            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String downloadFileContent(String url) throws Exception {
        URL website = new URL(url);
        URLConnection connection = website.openConnection();

        BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

        StringBuilder response = new StringBuilder();
        String inputLine;

        while ((inputLine = in.readLine()) != null)
            response.append(inputLine);

        in.close();

        return response.toString();
    }

    public Date getNextUpdate() {
        return m_nextUpdate;
    }

    public String getStatus() {
        return m_updateStatus;
    }

    public boolean isRunning() {
        return m_isRunning;
    }

    private void run() {
        if (m_isRunning)
            return;

        m_isRunning = true;

        try {
            long startTime = System.currentTimeMillis();

            LOGGER.info("Start updating profiles...");

            m_nextUpdate = new Date(startTime + m_updatePeriod);

            String osmFile = null;
            String datasource = m_config.DataSource;

            FileUtility.makeDirectory(m_config.WorkingDirectory);

            String md5Sum = null;
            String newMd5Sum = null;
            boolean skipUpdate = false;

            File fileLastUpdate = Paths.get(m_config.WorkingDirectory, "last-update.md5").toFile();
            if (fileLastUpdate.exists())
                md5Sum = FileUtils.readFileToString(fileLastUpdate);

            if (datasource.contains("http")) {
                m_updateStatus = "donwloading data";

                try {
                    newMd5Sum = downloadFileContent(datasource + ".md5");
                } catch (Exception ex2) {

                }

                if (md5Sum != null && newMd5Sum != null && md5Sum.contains(newMd5Sum))
                    skipUpdate = true;

                if (!skipUpdate) {
                    Path path = Paths.get(m_config.WorkingDirectory, FileUtility.getFileName(new URL(datasource)));

                    try {
                        downloadFile(datasource, path.toFile());
                    } catch (Exception ex) {
                        LOGGER.warning(ex.getMessage());

                        Thread.sleep(300000);

                        m_isRunning = false;
                        run();

                        return;
                    }

                    osmFile = path.toString();
                }
            } else {
                File file = new File(datasource + ".md5");
                newMd5Sum = file.exists() ? FileUtils.readFileToString(file) : FileUtility.getMd5OfFile(datasource);

                if (md5Sum != null && newMd5Sum != null && md5Sum.contains(newMd5Sum))
                    skipUpdate = true;

                if (!skipUpdate) {
                    file = new File(datasource);
                    Path path = Paths.get(m_config.WorkingDirectory, file.getName());

                    // make a local copy of the file
                    FileUtils.copyFile(file, path.toFile());

                    osmFile = path.toString();
                }
            }

            if (!skipUpdate) {
                if (Helper.isEmpty(newMd5Sum))
                    newMd5Sum = FileUtility.getMd5OfFile(osmFile);

                md5Sum = newMd5Sum;
                File file = new File(osmFile);
                String newFileStamp = Long.toString(file.length());

                String tempGraphLocation = Paths.get(m_config.WorkingDirectory, "graph").toString();

                try {
                    // Clear directory from a previous build
                    File fileGraph = new File(tempGraphLocation);
                    if (fileGraph.exists())
                        FileUtils.deleteDirectory(fileGraph);
                } catch (Exception ex) {
                }

                FileUtility.makeDirectory(tempGraphLocation);

                RoutingProfileLoadContext loadCntx = new RoutingProfileLoadContext();
                int nUpdatedProfiles = 0;

                for (RoutingProfile profile : m_routeProfiles.getUniqueProfiles()) {
                    RouteProfileConfiguration rpc = profile.getConfiguration();

                    Path pathTimestamp = Paths.get(rpc.getGraphPath(), "stamp.txt");
                    File file2 = pathTimestamp.toFile();
                    if (file2.exists()) {
                        String oldFileStamp = FileUtils.readFileToString(file2);
                        if (newFileStamp.equals(oldFileStamp))
                            continue;
                    }

                    if (m_updatePeriod > 0) {
                        StorableProperties storageProps = profile.getGraphProperties();
                        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

                        Date importDate = df.parse(storageProps.get("osmreader.import.date"));

                        long diff = startTime - importDate.getTime();

                        if (!DebugUtility.isDebug()) {
                            if (diff < m_updatePeriod)
                                continue;
                        }
                    }

                    try {
                        m_updateStatus = "preparing profile '" + rpc.getProfiles() + "'";

                        RouteProfileConfiguration rpcNew = rpc.clone();
                        rpcNew.setGraphPath(tempGraphLocation);
                        GraphHopper gh = RoutingProfile.initGraphHopper(osmFile, rpcNew,
                                RoutingProfileManager.getInstance().getProfiles(), loadCntx);

                        if (gh != null) {
                            profile.updateGH(gh);

                            if (RealTrafficDataProvider.getInstance().isInitialized()) {
                                m_updateStatus += ". Performing map matching...";
                                RealTrafficDataProvider.getInstance().updateGraphMatching(profile,
                                        profile.getGraphLocation());
                            }

                            nUpdatedProfiles++;
                        }
                    } catch (Exception ex) {
                        LOGGER.severe("Failed to update graph profile. Message:" + ex.getMessage()
                                + "; StackTrace: " + StackTraceUtility.getStackTrace(ex));
                    }

                    m_updateStatus = null;
                }

                loadCntx.releaseElevationProviderCacheAfterAllVehicleProfilesHaveBeenProcessed();

                FileUtils.writeStringToFile(fileLastUpdate, md5Sum);

                long seconds = (System.currentTimeMillis() - startTime) / 1000;
                LOGGER.info(nUpdatedProfiles + " of " + m_routeProfiles.size() + " profiles were updated in "
                        + seconds + " s.");

                m_updateStatus = "Last update on " + new Date() + " took " + seconds + " s.";
            } else {
                LOGGER.info("No new data is available.");
            }

        } catch (Exception ex) {
            LOGGER.warning(ex.getMessage());
        }

        LOGGER.info("Next route profiles update is scheduled on " + m_nextUpdate.toString());

        m_isRunning = false;
    }

    public void stop() {
        if (m_timer != null) {
            m_timer.cancel();
            m_timer = null;
        }
    }

    public void destroy() {
        stop();
    }
}