com.comcast.cdn.traffic_control.traffic_monitor.util.PeriodicResourceUpdater.java Source code

Java tutorial

Introduction

Here is the source code for com.comcast.cdn.traffic_control.traffic_monitor.util.PeriodicResourceUpdater.java

Source

/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.comcast.cdn.traffic_control.traffic_monitor.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;

import com.comcast.cdn.traffic_control.traffic_monitor.config.ConfigHandler;

/** 
 * 
 * @author jlaue
 *
 */
public class PeriodicResourceUpdater {
    private static final Logger LOGGER = Logger.getLogger(PeriodicResourceUpdater.class);
    private boolean isActive = true;
    private boolean running = false;

    protected IModel<Long> pollingInterval;
    protected IModel<String> host;

    //   static protected ScheduledExecutorService executorService;
    //   protected ScheduledFuture<?> scheduledService;

    public PeriodicResourceUpdater(final IModel<Long> interval) {
        pollingInterval = interval;
    }

    private final List<UpdateModel> umList = new ArrayList<UpdateModel>();

    private static class UpdateModel {
        protected List<Model<String>> urlList = new LinkedList<Model<String>>();
        protected String databaseLocation;
        private Updatable listener;
        private boolean hasBeenLoaded = false;

        private void putCurrent() {
            final File existingDB = ConfigHandler.getInstance().getDbFile(databaseLocation);

            if (existingDB.exists()) {
                LOGGER.warn("loading: " + existingDB.getAbsolutePath());
                listener.update(existingDB);
            }

            hasBeenLoaded = true;
        }
    }

    public void add(final Updatable listener, final Model<String> url, final String location) {
        final UpdateModel um = new UpdateModel();
        um.listener = listener;
        um.urlList.add(url);
        um.databaseLocation = location;
        add(um);
    }

    public void add(final Updatable listener, final String[] urla, final String location) {
        final UpdateModel um = new UpdateModel();
        um.listener = listener;
        for (String url : urla) {
            um.urlList.add(new Model<String>(url));
        }
        um.databaseLocation = location;
        add(um);
    }

    private void add(final UpdateModel um) {
        um.putCurrent();
        synchronized (umList) {
            umList.add(um);
        }
    }

    //   static {
    //      executorService = java.util.concurrent.Executors.newSingleThreadScheduledExecutor();
    //   }

    public void destroy() {
        //      executorService.shutdownNow();
        isActive = false;
        mainThread.interrupt();
        while (running) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
            }
        }
    }

    final private Runnable updater = new Runnable() {
        @Override
        public void run() {
            running = true;
            while (isActive) {
                try {
                    synchronized (umList) {
                        for (UpdateModel um : umList) {
                            if (!isActive) {
                                running = false;
                                return;
                            }
                            updateDatabase(um);
                        }
                    }
                } catch (Exception e) {
                    LOGGER.warn("error", e);
                }
                try {
                    Thread.sleep(getPollingInterval());
                } catch (InterruptedException e) {
                }
            }
            running = false;
        }
    };
    private Thread mainThread;

    public long getPollingInterval() {
        return pollingInterval.getObject().longValue();
    }

    public void init() {
        mainThread = new Thread(updater);
        mainThread.start();
    }

    public void forceUpdate() {
        mainThread.interrupt();
    }

    protected File fetchFile(final String url) throws IOException {
        return Fetcher.downloadFile(url);
    }

    public boolean updateDatabase(final UpdateModel um) {
        final File existingDB = ConfigHandler.getInstance().getDbFile(um.databaseLocation);
        File newDB = null;
        try {
            if (um.hasBeenLoaded) {
                int urlIndex = (int) (Math.random() * um.urlList.size());
                for (int i = 0; i < um.urlList.size(); i++) {
                    final String url = um.urlList.get(urlIndex).getObject();
                    try {
                        newDB = fetchFile(url);
                    } catch (Exception e) {
                        LOGGER.error("Error with '" + url + "' : " + e);
                        urlIndex = (urlIndex + 1) % um.urlList.size();
                        continue;
                    }
                    break;
                }
                if (newDB != null && !filesEqual(existingDB, newDB)) {
                    if (um.listener.update(newDB)) {
                        copyDatabase(existingDB, newDB);
                        LOGGER.debug("File saved: " + existingDB.getAbsolutePath());
                    } else {
                        LOGGER.debug("File rejected: " + existingDB.getAbsolutePath());
                        Fetcher.clearTmCookie();
                    }
                } else {
                    LOGGER.debug("File unchanged: " + existingDB.getAbsolutePath());
                }
                return true;
            }
        } catch (final Exception e) {
            LOGGER.warn(e.getMessage(), e);
        } finally {
            if (newDB != null) {
                newDB.delete();
            }
        }
        return false;
    }

    static boolean filesEqual(final File a, final File b) throws IOException {
        if (!a.exists() && !b.exists()) {
            return true;
        }
        if (!a.exists() || !b.exists()) {
            return false;
        }
        if (a.length() != b.length()) {
            return false;
        }
        FileInputStream fis = new FileInputStream(a);
        final String md5a = org.apache.commons.codec.digest.DigestUtils.md5Hex(fis);
        fis.close();
        fis = new FileInputStream(b);
        final String md5b = org.apache.commons.codec.digest.DigestUtils.md5Hex(fis);
        fis.close();
        if (md5a.equals(md5b)) {
            return true;
        }
        return false;
    }

    static void copyDatabase(final File existingDB, final File newDB) throws IOException {
        final FileInputStream in = new FileInputStream(newDB);
        final FileOutputStream out = new FileOutputStream(existingDB);
        final FileLock lock = out.getChannel().tryLock();
        if (lock != null) {
            LOGGER.info("Updating location database.");
            IOUtils.copy(in, out);
            existingDB.setReadable(true, false);
            existingDB.setWritable(true, false);
            lock.release();
            LOGGER.info("Successfully updated location database.");
        } else {
            LOGGER.info("Location database locked by another process.");
        }
        IOUtils.closeQuietly(in);
        IOUtils.closeQuietly(out);
    }
}