/*
* Copyright (c) 2014 tabletoptool.com team.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* rptools.com team - initial implementation
* tabletoptool.com team - further development
*/
package com.t3.transfer;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
public class AssetTransferManager {
private Map<Serializable, AssetConsumer> consumerMap = new HashMap<Serializable, AssetConsumer>();
private List<ConsumerListener> consumerListenerList = new CopyOnWriteArrayList<ConsumerListener>();
private List<AssetProducer> producerList = new LinkedList<AssetProducer>();
/**
* Clear out all existing consumers and producers
*/
public synchronized void flush() {
consumerMap.clear();
producerList.clear();
}
/**
* Add a new producer to the chunk queue. Assumes that the header has already been transferred
* to the consumer. Producer chunks can then be retrieved via nextChunk()
*/
public synchronized void addProducer(AssetProducer producer) {
producerList.add(producer);
}
/**
* Get the next chunk from the available producers
* @param size size of the data to retrieve
* @throws IOException
*/
public synchronized AssetChunk nextChunk(int size) throws IOException {
if (producerList.size() == 0) {
return null;
}
AssetProducer producer = producerList.remove(0);
AssetChunk chunk = producer.nextChunk(size);
if (!producer.isComplete()) {
producerList.add(producer);
}
return chunk;
}
/**
* Add the corresponding consumer that is expecting to receive chunks.
* Add a ConsumerListener to know when the asset is complete
*/
public synchronized void addConsumer(AssetConsumer consumer) {
if (consumerMap.get(consumer.getId()) != null) {
throw new IllegalArgumentException("Asset is already being downloaded: " + consumer.getId());
}
consumerMap.put(consumer.getId(), consumer);
for (ConsumerListener listener : consumerListenerList) {
listener.assetAdded(consumer.getId());
}
}
/**
* Update the appropriate asset. To be notified when the asset is complete add a ConsumerListener.
* When the asset is complete it will be removed from the internal map automatically
* @throws IOException
*/
public synchronized void update(AssetChunk chunk) throws IOException {
AssetConsumer consumer = consumerMap.get(chunk.getId());
if (consumer == null) {
throw new IllegalArgumentException("Not expecting chunk: " + chunk.getId());
}
consumer.update(chunk);
if (consumer.isComplete()) {
consumerMap.remove(consumer.getId());
for (ConsumerListener listener : consumerListenerList) {
listener.assetComplete(consumer.getId(), consumer.getName(), consumer.getFilename());
}
} else {
for (ConsumerListener listener : consumerListenerList) {
listener.assetUpdated(consumer.getId());
}
}
}
/**
* Get a list of current asset consumers, this is a good way to know what's going on in the system
*/
public synchronized List<AssetConsumer> getAssetConsumers() {
return new ArrayList<AssetConsumer>(consumerMap.values());
}
public void addConsumerListener(ConsumerListener listener) {
consumerListenerList.add(listener);
}
public void removeConsumerListener(ConsumerListener listener) {
consumerListenerList.remove(listener);
}
}