ch.cyberduck.core.transfer.TransferQueue.java Source code

Java tutorial

Introduction

Here is the source code for ch.cyberduck.core.transfer.TransferQueue.java

Source

package ch.cyberduck.core.transfer;

/*
 * Copyright (c) 2002-2010 David Kocher. All rights reserved.
 *
 * http://cyberduck.ch/
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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.
 *
 * Bug fixes, suggestions and comments should be sent to:
 * dkocher@cyberduck.ch
 */

import ch.cyberduck.core.LocaleFactory;
import ch.cyberduck.core.ProgressListener;
import ch.cyberduck.core.local.ApplicationBadgeLabeler;
import ch.cyberduck.core.local.ApplicationBadgeLabelerFactory;
import ch.cyberduck.core.notification.NotificationService;
import ch.cyberduck.core.notification.NotificationServiceFactory;
import ch.cyberduck.core.preferences.PreferencesFactory;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public final class TransferQueue {
    private static final Logger log = Logger.getLogger(TransferQueue.class);

    private final ApplicationBadgeLabeler label = ApplicationBadgeLabelerFactory.get();

    private BlockingQueue<Transfer> running;

    private final NotificationService notification = NotificationServiceFactory.get();

    private final List<Transfer> temporary = new ArrayList<Transfer>();

    private final Map<Transfer, Thread> threads = new HashMap<Transfer, Thread>();

    public TransferQueue() {
        this(PreferencesFactory.get().getInteger("queue.maxtransfers"));
    }

    public TransferQueue(final int size) {
        this.running = new ArrayBlockingQueue<Transfer>(size, true);
    }

    /**
     * Idle this transfer until a free slot is available depending on
     * the maximum number of concurrent transfers allowed in the Preferences.
     *
     * @param t This transfer should respect the settings for maximum number of transfers
     */
    public void add(final Transfer t, final ProgressListener listener) {
        if (log.isDebugEnabled()) {
            log.debug(String.format("Add transfer %s to queue", t));
        }
        if (0 == running.remainingCapacity()) {
            if (log.isInfoEnabled()) {
                log.info(String.format("Queuing transfer %s", t));
            }
            listener.message(
                    LocaleFactory.localizedString("Maximum allowed connections exceeded. Waiting", "Status"));
            notification.notify("Transfer queued", t.getName());
        }
        // The maximum number of transfers is already reached. Wait for transfer slot.
        try {
            threads.put(t, Thread.currentThread());
            running.put(t);
        } catch (InterruptedException e) {
            log.error(String.format("Error waiting for slot in queue. %s", e.getMessage()));
        } finally {
            threads.remove(t);
        }
        if (log.isInfoEnabled()) {
            log.info(String.format("Released from queue %s", t));
        }
        label.badge(String.valueOf(running.size()));
    }

    /**
     * @param t Transfer to drop from queue
     */
    public void remove(final Transfer t) {
        if (log.isDebugEnabled()) {
            log.debug(String.format("Remove %s from queue", t));
        }
        if (running.remove(t)) {
            if (0 == running.size()) {
                label.badge(StringUtils.EMPTY);
            } else {
                label.badge(String.valueOf(running.size()));
            }
        } else {
            final Thread removed = threads.remove(t);
            if (removed != null) {
                log.warn(String.format("Interrupt thread %s for transfer %s", removed, t));
                removed.interrupt();
            }
            temporary.remove(t);
        }
        // Transfer has finished.
        this.poll();
    }

    /**
     * Resize queue with current setting in preferences.
     */
    public void resize(int newsize) {
        if (log.isDebugEnabled()) {
            log.debug(String.format("Resize queue to %d", newsize));
        }
        final int drained = running.drainTo(temporary);
        if (log.isDebugEnabled()) {
            log.debug(String.format("Drained %d elements", drained));
        }
        running.clear();
        running = new ArrayBlockingQueue<Transfer>(newsize);
        this.poll();
    }

    /**
     * Poll temporary queue
     */
    private void poll() {
        if (log.isDebugEnabled()) {
            log.debug("Polling overflow queue");
        }
        temporary.removeIf(transfer -> running.offer(transfer));
    }
}