displayclient.DownloadManager.java Source code

Java tutorial

Introduction

Here is the source code for displayclient.DownloadManager.java

Source

/*
 * Xibo - Digital Signage - http://www.xibo.org.uk
 * Copyright (C) 2008-2015 Alex Harrington
 *
 * This file is part of Xibo.
 *
 * Xibo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version. 
 *
 * Xibo 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Xibo.  If not, see <http://www.gnu.org/licenses/>.
 */
package displayclient;

/**
 *
 * @author Alex Harrington - Spring Signage Ltd
 */
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.Filters;
import org.jdom2.input.SAXBuilder;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;

public class DownloadManager extends Thread {

    protected boolean running = true;
    protected int numThreads;
    protected int numThreadsLimit;
    private ArrayList<FileFetcher> runningDownloads;
    private final static Logger log = Logger.getLogger(DownloadManager.class.getName());
    protected final DisplayClient DC;

    public DownloadManager(DisplayClient parent) {
        log.addHandler(new ConsoleHandler());
        log.setLevel(Level.ALL);
        this.DC = parent;

        this.numThreads = 0;
        this.runningDownloads = new ArrayList<>();

        log.log(Level.INFO, "Init. Max Download threads = {0}", this.numThreadsLimit);
    }

    @Override
    public void run() {
        int updateInterval = Integer.parseInt(DisplayClient.prop.getProperty("CollectInterval"));
        log.log(Level.INFO, "Run. Collection Interval = {0}", updateInterval);

        while (running) {
            // Update thread limits and updateInterval incase they changed on
            // instruction from the CMS
            this.numThreadsLimit = Integer.parseInt(DisplayClient.prop.getProperty("MaxConcurrentDownloads"));
            updateInterval = Integer.parseInt(DisplayClient.prop.getProperty("CollectInterval"));

            String response = "";
            try {
                response = this.DC.XMDS.RequiredFiles(DisplayClient.prop.getProperty("ServerKey"),
                        DisplayClient.prop.getProperty("HardwareKey"));
                log.log(Level.FINE, "DownloadManager: xmds.requiredFiles => {0}", response);
            } catch (Exception ex) {
                log.log(Level.FINEST, "DownloadManager: xmds.requiredFiles => {0}", response);
                log.log(Level.WARNING, "DownloadManager: Could not connect to XMDS at {0}",
                        DisplayClient.prop.getProperty("ServerUri"));
                log.log(Level.WARNING, "DownloadManager: xmds.requiredFiles => {0}", ex);
                continue;
            }

            Document doc;
            Iterator iter;

            if (!response.equals("")) {
                // Code here to parse the returned XML
                SAXBuilder sb = new SAXBuilder();

                try {
                    doc = sb.build(new StringReader(response));

                    // Build an iterator over the files section of the response
                    XPathFactory xFactory = XPathFactory.instance();

                    XPathExpression<Element> expr = xFactory.compile("//file", Filters.element());
                    List<Element> files = expr.evaluate(doc);
                    for (Element n : files) {

                        FileFetcher f = null;

                        if (n.getAttributeValue("download").equalsIgnoreCase("http")) {
                            f = new HttpFileFetcher(this, n);
                        } else {
                            f = new XmdsFileFetcher(this, n);
                        }

                        Boolean skip = false;

                        // Check to see if there is already a download
                        // running for this file ID. If there is, skip it.
                        for (FileFetcher tmp : runningDownloads) {
                            try {
                                if (f.getID() == tmp.getID()) {
                                    skip = true;
                                    log.log(Level.FINEST,
                                            "DownloadManager: FileFetcher {0} is still running from previous collection. Skipping.",
                                            f.getID());
                                }
                            } catch (NullPointerException e) {
                                // The download completed while we were testing for it.
                                // Ignore it.
                                skip = true;
                            }
                        }

                        if (!skip) {
                            f.start();
                            this.runningDownloads.add(f);
                            this.numThreads++;
                        }

                        while (this.numThreads >= (this.numThreadsLimit - 1)) {
                            // Thread throttling
                            // Sleep until there is a spare space for a new thread.
                            try {
                                log.log(Level.FINE, "DownloadManager: {0} downloads in progress. Sleeping.",
                                        this.numThreadsLimit);
                                sleep(5000);
                            } catch (InterruptedException e) {
                            }
                        }
                    }
                } catch (JDOMException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // Make sure updateInterval is sane.
            if (updateInterval < 30) {
                updateInterval = 30;
            }

            // Sleep for "updateInterval" seconds before trying again.
            try {
                sleep(updateInterval * 1000);
            } catch (InterruptedException e) {
            }
        }
    }

    protected void threadCompleteNotify(FileFetcher f) {
        log.log(Level.FINE, "DownloadManager: FileFetcher {0} completed.", f.getID());
        if (this.numThreads > 0) {
            this.numThreads = this.numThreads - 1;
        }
        this.runningDownloads.remove(f);
    }
}