/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2014, Geomatys
*
* This library 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;
* version 2.1 of the License.
*
* 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.
*/
package org.geotoolkit.coverage.xmlstore;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.util.ArgumentChecks;
import org.geotoolkit.image.io.XImageIO;
import javax.imageio.ImageWriter;
import java.awt.image.RenderedImage;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
/**
* A thread which will write given tiles into the specified pyramid set.
* /!\ It won't stop until you provide it a poisonous object {@link org.geotoolkit.coverage.xmlstore.XMLTileWriter.MissingInfo}.
*
* @author Alexis Manin (Geomatys)
*/
public class XMLTileWriter implements Runnable {
protected XMLCoverageReference targetRef;
protected BlockingQueue<XMLTileInfo> tileQueue;
/**
* A new runnable which role is to write tiles into a specific pyramid set.
* @param tileQueue The queue containing the tiles to write as all needed information to do so.
* @param targetRef The reference to the destination pyramid set.
*/
XMLTileWriter(BlockingQueue<XMLTileInfo> tileQueue, XMLCoverageReference targetRef) {
ArgumentChecks.ensureNonNull("Tile queue", tileQueue);
ArgumentChecks.ensureNonNull("Pyramid set reference", targetRef);
this.tileQueue = tileQueue;
this.targetRef = targetRef;
}
@Override
public void run() {
final Thread currentThread = Thread.currentThread();
ImageWriter writer = null;
try {
writer = XImageIO.getWriterByFormatName(targetRef.getPyramidSet().getFormatName(), null, null);
takeMethod(writer, currentThread);
} catch (InterruptedException e) {
currentThread.interrupt();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (writer != null) writer.dispose();
}
}
/**
* Core method for tile writing. This function uses the "draining algorithm", which will peek tiles by set.
*
* @param writer The {@link javax.imageio.ImageWriter} to use to write tiles in the mosaics.
* @param currentThread The current thread in which the runnable is running. Used to get interruption status.
* @throws DataStoreException If tile creation fails.
*/
private void drainMethod(final ImageWriter writer, final Thread currentThread) throws DataStoreException {
final LinkedList<XMLTileInfo> tiles = new LinkedList<>();
XMLTileInfo info;
try {
while (!currentThread.isInterrupted()) {
tileQueue.drainTo(tiles);
while ((info = tiles.poll()) != null) {
if (info instanceof MissingInfo || currentThread.isInterrupted()) {
return;
}
info.mosaic.createTile(info.tX, info.tY, info.data, writer);
}
}
} finally {
targetRef.save();
}
}
/**
* Core method for tile writing. This function uses a simple algorithm which will peek tiles one by one.
*
* @param writer The {@link javax.imageio.ImageWriter} to use to write tiles in the mosaics.
* @param currentThread The current thread in which the runnable is running. Used to get interruption status.
* @throws DataStoreException If tile creation fails.
* @throws InterruptedException If the thread in which we run has been intercepted while we were waiting for a tile from the queue.
*/
private void takeMethod(final ImageWriter writer, final Thread currentThread) throws DataStoreException, InterruptedException {
XMLTileInfo info;
try {
while (!currentThread.isInterrupted()) {
info = tileQueue.take();
if (info == null || info instanceof MissingInfo) {
break;
}
info.mosaic.createTile(info.tX, info.tY, info.data, writer);
}
} finally {
targetRef.save();
}
}
/**
* An object which aim is to contain a tile to write, as all the information about its position in the target pyramid set.
*/
public static class XMLTileInfo {
int tX;
int tY;
final XMLMosaic mosaic;
RenderedImage data;
public XMLTileInfo(int tX, int tY, RenderedImage data, XMLMosaic mosaic) {
this.tX = tX;
this.tY = tY;
this.data = data;
this.mosaic = mosaic;
}
}
/**
* A poisonous object to specify to the thread that we don't have any more data to write.
*/
public static class MissingInfo extends XMLTileInfo {
public MissingInfo() {
super(-1, -1, null, null);
}
}
}