/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2013, 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.storage.coverage;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.coverage.io.CoverageReader;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.coverage.io.GridCoverageReader;
import org.opengis.util.GenericName;
/**
* Abstract coverage reference which recycle readers.
*
* @author Johann Sorel (Geomatys)
*/
public abstract class RecyclingCoverageReference extends AbstractCoverageReference{
private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.storage.coverage");
/**
* Maximum number of readers to keep.
*/
private static final int MAX_ELEMENTS = 3;
/**
* The pool of coverage reader. This pool is initially empty and will be filled with elements as needed.
* readers (if any) shall be fetched using the {@link Deque#poll()} method and, after use,
* given back to the pool using the {@link Deque#push(Object)} method.
*
* <p>This queue must be a thread-safe implementation, since it will not be invoked in
* synchronized block.</p>
*
* @see #acquireReader()
* @see #recycle(GridCoverageReader)
*/
private final ConcurrentLinkedDeque<CoverageReader> readers = new ConcurrentLinkedDeque<>();
public RecyclingCoverageReference(CoverageStore store, GenericName name) {
super(store, name);
}
/**
* {@inheritDoc}
* @return new GridCoverageReader or an a recycled one.
*/
@Override
public final GridCoverageReader acquireReader() throws CoverageStoreException {
GridCoverageReader reader = (GridCoverageReader) readers.poll();
if (reader == null) {
reader = createReader();
}
return reader;
}
/**
* Check if reader to recycle is reusable and then cache it for other users.
* If input reader can't be reused, for example he was closed or lost his input, it will
* be disposed and not make available for other users.
*
* @param reader that can be reused
*/
@Override
public final void recycle(CoverageReader reader) {
try {
checkReader(reader);
readers.push(reader);
removeExpired(readers);
} catch (CoverageStoreException e) {
LOGGER.log(Level.WARNING, "Reader not recycled will be disposed. Not recycled cause : "+e.getMessage(), e);
dispose(reader);
}
}
/**
* Create a new reader.
*/
protected abstract GridCoverageReader createReader() throws CoverageStoreException;
/**
* Verify if reader is still operational and usable.
* For example if reader is not valid if it was disposed or closed by CoverageReader user.
* This method must ensure that input CoverageReader can be reused safely by another user.
*
* @param reader CoverageReader to test
* @throws CoverageStoreException if reader is not reusable or something
* goes wrong during reader test.
*/
protected void checkReader(CoverageReader reader) throws CoverageStoreException {
}
/**
* Removes expired readers from the given queue.
*
* @param <T> {@code GridCoverageReader} type.
* @param queue The queue from which to remove expired readers.
* @param now Current value of {@link System#nanoTime()}.
* @return {@code true} if the queue became empty as a result of this method call.
*/
private boolean removeExpired(final Deque<CoverageReader> queue) {
while (queue.size()>MAX_ELEMENTS) {
final CoverageReader next = queue.pollLast();
if(next==null)continue;
dispose(next);
}
return true;
}
/**
* Dispose all readers in the queue if any.
*
* @throws Throwable
*/
@Override
protected void finalize() throws Throwable {
while(!readers.isEmpty()){
final CoverageReader next = readers.pollLast();
if(next==null)continue;
dispose(next);
}
super.finalize();
}
}