/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.template;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.util.logging.Logging;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.TemplateCollectionModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
import freemarker.template.TemplateModelIterator;
import freemarker.template.TemplateSequenceModel;
/**
*
* Create FeatureCollection Template Model without copying features to memory
* When using this in a FeatureWrapper, it is necessary to call purge() method after
* processing template, to close any open database connections
*
* @author Niels Charlier, Curtin University of Technology
*
*/
public class DirectTemplateFeatureCollectionFactory implements FeatureWrapper.TemplateFeatureCollectionFactory<DirectTemplateFeatureCollectionFactory.TemplateFeatureCollection> {
static Logger LOGGER = Logging.getLogger(DirectTemplateFeatureCollectionFactory.class);
/**
* thread local to track open iterators
*/
static ThreadLocal<List<TemplateFeatureIterator>> ITERATORS =
new ThreadLocal<List<TemplateFeatureIterator>>();
public void purge() {
List<TemplateFeatureIterator> its = ITERATORS.get();
if (its != null) {
for (TemplateFeatureIterator it : its) {
try {
it.close();
}
catch(Throwable t) {
LOGGER.log(Level.WARNING, "Error closing iterator", t);
}
}
its.clear();
ITERATORS.remove();
}
}
public DirectTemplateFeatureCollectionFactory() {
}
public TemplateCollectionModel createTemplateFeatureCollection(FeatureCollection collection,
BeansWrapper wrapper) {
return new TemplateFeatureCollection(collection, wrapper);
}
protected class TemplateFeatureCollection implements TemplateCollectionModel, TemplateSequenceModel {
protected BeansWrapper wrapper;
protected FeatureCollection collection;
protected TemplateFeatureIterator indexIterator = null;
protected int currentIndex = -1;
protected TemplateModel currentItem = null;
public TemplateFeatureCollection(FeatureCollection collection, BeansWrapper wrapper) {
this.collection = collection;
this.wrapper = wrapper;
}
public TemplateModelIterator iterator() throws TemplateModelException {
TemplateFeatureIterator it = new TemplateFeatureIterator(collection.features(), wrapper);
List<TemplateFeatureIterator> open = ITERATORS.get();
if (open == null) {
open = new LinkedList();
ITERATORS.set(open);
}
open.add(it);
return it;
}
@Override
public TemplateModel get(int index) throws TemplateModelException {
if (currentIndex > index ) {
//we have gone backwards, close iterator and clean up as we will need to start over
if (indexIterator != null) {
ITERATORS.get().remove(indexIterator);
try {
indexIterator.close();
}
catch(Throwable t) {
LOGGER.log(Level.WARNING, "Error closing iterator", t);
}
indexIterator = null;
}
currentIndex = -1;
currentItem = null;
}
if (indexIterator == null) {
indexIterator = (TemplateFeatureIterator) iterator();
}
while (currentIndex < index && indexIterator.hasNext()) {
//forward to correct index
currentItem = indexIterator.next();
currentIndex++;
}
return index == currentIndex ? currentItem : null;
}
@Override
public int size() throws TemplateModelException {
return collection.size();
}
}
protected class TemplateFeatureIterator implements TemplateModelIterator {
protected BeansWrapper wrapper;
protected FeatureIterator iterator;
public TemplateFeatureIterator(FeatureIterator iterator, BeansWrapper wrapper) {
this.iterator = iterator;
this.wrapper = wrapper;
}
public TemplateModel next() throws TemplateModelException {
return wrapper.wrap(iterator.next());
}
public boolean hasNext() throws TemplateModelException {
return iterator.hasNext();
}
public void close() {
iterator.close();
}
}
}