package com.vividsolutions.jump.workbench.model.cache;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import javax.swing.SwingUtilities;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.datastore.*;
import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.feature.FeatureCollection;
import com.vividsolutions.jump.feature.FeatureSchema;
import com.vividsolutions.jump.io.FeatureInputStream;
import com.vividsolutions.jump.util.ListWrapper;
import com.vividsolutions.jump.workbench.datastore.ConnectionDescriptor;
import com.vividsolutions.jump.workbench.datastore.ConnectionManager;
import com.vividsolutions.jump.workbench.ui.plugin.AddNewLayerPlugIn;
public class DynamicFeatureCollection implements FeatureCollection {
private Integer featureLimit = null;
private FilterQuery spatialQuery;
private ConnectionManager connectionManager;
private ConnectionDescriptor connectionDescriptor;
public DynamicFeatureCollection(ConnectionDescriptor connectionDescriptor,
ConnectionManager connectionManager, FilterQuery spatialQuery) {
this.connectionManager = connectionManager;
this.connectionDescriptor = connectionDescriptor;
this.spatialQuery = spatialQuery;
}
public void setFeatureLimit(Integer featureLimit) {
this.featureLimit = featureLimit;
}
private volatile Object currentQueryContext;
private FeatureSchema schema = AddNewLayerPlugIn
.createBlankFeatureCollection().getFeatureSchema();
public FeatureSchema getFeatureSchema() {
return schema;
}
public List query(Envelope envelope) {
final Object myQueryContext = new Object();
currentQueryContext = myQueryContext;
Envelope layerExtents = getEnvelope();
if(layerExtents == null || layerExtents.isNull() || layerExtents.contains(envelope)){
spatialQuery.setFilterGeometry(new GeometryFactory().toGeometry(envelope));
}else{
// we are asking for too much data ...
spatialQuery.setFilterGeometry(new GeometryFactory().toGeometry(layerExtents.intersection(envelope)));
}
// Q: When do we close the stream? A: When a new stream is
// requested. Implication: You cannot have two streams active from
// the same DynamicFeatureCollection. But JUMP does not need this
// capability. [Jon Aquino 2005-03-02]
final FeatureInputStream myFeatureInputStream;
try {
myFeatureInputStream = connectionManager.getOpenConnection(
connectionDescriptor).execute(spatialQuery);
} catch (Exception e) {
throw new RuntimeException(e);
}
// Sometimes #execute takes a long time (e.g. SDE), and other calls to
// #query may have occurred. [Jon Aquino 2005-03-15]
if (myQueryContext != currentQueryContext) {
return Collections.EMPTY_LIST;
}
schema = myFeatureInputStream.getFeatureSchema();
return new ListWrapper() {
public Collection getCollection() {
// Implement #iterator only [Jon Aquino 2005-03-03]
throw new UnsupportedOperationException();
}
public Iterator iterator() {
return new Iterator() {
private int featuresReturned = 0;
private boolean featureInputStreamOpen = true;
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
try {
if (featureLimit != null
&& featuresReturned >= featureLimit
.intValue()) {
closeFeatureInputStream();
return false;
}
if (myQueryContext != currentQueryContext) {
closeFeatureInputStream();
return false;
}
// Explicitly check if the stream is closed;
// otherwise #hasNext will throw a
// NullPointerException.
// [Jon Aquino 2005-03-03]
if (!featureInputStreamOpen) {
return false;
}
if (!myFeatureInputStream.hasNext()) {
closeFeatureInputStream();
return false;
}
return true;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private void closeFeatureInputStream() throws Exception {
myFeatureInputStream.close();
featureInputStreamOpen = false;
}
public Object next() {
assertNotInGUIThread();
if (!hasNext()) {
throw new NoSuchElementException();
}
try {
featuresReturned++;
return myFeatureInputStream.next();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
}
};
}
public void add(Feature feature) {
throw new UnsupportedOperationException();
}
public void addAll(Collection features) {
throw new UnsupportedOperationException();
}
public void removeAll(Collection features) {
throw new UnsupportedOperationException();
}
public void remove(Feature feature) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
public Collection remove(Envelope env) {
throw new UnsupportedOperationException();
}
/**
* @see com.vividsolutions.jump.feature.FeatureCollection#getEnvelope()
*/
public Envelope getEnvelope() {
DataStoreConnection dsc = null;
try {
dsc = connectionManager.getOpenConnection(connectionDescriptor);
} catch (Exception e1) {
// ignore
return new Envelope();
}
Envelope e = null;
if(dsc != null){
DataStoreMetadata dsm = dsc.getMetadata();
if(dsm != null && spatialQuery != null)
e = dsm.getExtents(spatialQuery.getDatasetName(), spatialQuery.getGeometryAttributeName());
}
return e;
}
public int size() {
throw new UnsupportedOperationException();
}
public boolean isEmpty() {
throw new UnsupportedOperationException();
}
public List getFeatures() {
throw new UnsupportedOperationException();
}
public Iterator iterator() {
throw new UnsupportedOperationException();
}
private void assertNotInGUIThread() {
Assert.isTrue(!SwingUtilities.isEventDispatchThread(),
"This operation should be done outside of the GUI thread");
}
}