/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2012-2015, Open Source Geospatial Foundation (OSGeo)
*
* 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.geotools.data.store;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.geotools.data.BatchFeatureEvent;
import org.geotools.data.DataStore;
import org.geotools.data.DataUtilities;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.FeatureEvent;
import org.geotools.data.FeatureListener;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.NameImpl;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.WKTReader;
/**
* Tests events in autocommit and with transactions
*
* @author Niels Charlier, Scitus Development
*/
public class ContentFeatureSourceEventsTest extends AbstractContentTest {
private DefaultTransaction defaultTransaction;
private DefaultTransaction anotherTransaction;
private static class Listener implements FeatureListener {
String name;
List<FeatureEvent> events = new ArrayList<FeatureEvent>();
public Listener(String name) {
this.name = name;
}
public void changed(FeatureEvent featureEvent) {
this.events.add(featureEvent);
}
FeatureEvent getEvent(int i) {
return events.get(i);
}
}
@Before
public void setUp() {
defaultTransaction = new DefaultTransaction();
anotherTransaction = new DefaultTransaction();
}
@After
public void tearDown() {
defaultTransaction.close();
anotherTransaction.close();
}
@Test
public void testFeatureEventsAutoCommit() throws Exception {
DataStore store = new MockContentDataStore();
SimpleFeatureStore store1 = (SimpleFeatureStore) store.getFeatureSource(TYPENAME);
SimpleFeatureStore store2 = (SimpleFeatureStore) store.getFeatureSource(TYPENAME);
Listener listener1 = new Listener("one");
Listener listener2 = new Listener("two");
store1.addFeatureListener(listener1);
store2.addFeatureListener(listener2);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
final SimpleFeature feature = FEATURES.get(0);
Filter fidFilter = ff.id(feature.getIdentifier());
// test change
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
WKTReader reader = new WKTReader( geometryFactory );
Polygon geom = (Polygon) reader.read("POLYGON ((0 2, 1 0, 1 1, 0 1, 0 2))");
ReferencedEnvelope bounds = new ReferencedEnvelope();
bounds.include(feature.getBounds());
bounds.expandToInclude(geom.getEnvelopeInternal());
store1.modifyFeatures(new Name[]{new NameImpl("geom")},
new Object[]{geom}, fidFilter);
// test that both listeners get the event.
assertEquals(1, listener1.events.size());
assertEquals(1, listener2.events.size());
FeatureEvent event = listener1.getEvent(0);
assertEquals(bounds, event.getBounds());
assertEquals(FeatureEvent.Type.CHANGED, event.getType());
assertEquals(event, listener2.getEvent(0));
listener1.events.clear();
listener2.events.clear();
// test remove
store1.removeFeatures(fidFilter);
assertEquals(1, listener1.events.size());
assertEquals(1, listener2.events.size());
event = listener1.getEvent(0);
assertEquals(feature.getBounds(), event.getBounds());
assertEquals(FeatureEvent.Type.REMOVED, event.getType());
assertEquals(event, listener2.getEvent(0));
// test add
listener1.events.clear();
listener2.events.clear();
store1.addFeatures(DataUtilities.collection(feature));
assertEquals(1, listener1.events.size());
assertEquals(1, listener2.events.size());
event = listener1.getEvent(0);
assertEquals(feature.getBounds(), event.getBounds());
assertEquals(FeatureEvent.Type.ADDED, event.getType());
assertEquals(event, listener2.getEvent(0));
}
@Test
public void testFeatureEventsWithTransaction() throws Exception {
DataStore store = new MockContentDataStore();
SimpleFeatureStore store1 = (SimpleFeatureStore) store.getFeatureSource(TYPENAME);
SimpleFeatureStore store2 = (SimpleFeatureStore) store.getFeatureSource(TYPENAME);
store1.setTransaction(defaultTransaction);
store2.setTransaction(anotherTransaction);
Listener listener1 = new Listener("one");
Listener listener2 = new Listener("two");
store1.addFeatureListener(listener1);
store2.addFeatureListener(listener2);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
final SimpleFeature feature = FEATURES.get(0);
Filter fidFilter = ff.id(feature.getIdentifier());
// test change
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
WKTReader reader = new WKTReader( geometryFactory );
Polygon geom = (Polygon) reader.read("POLYGON ((0 2, 1 0, 1 1, 0 1, 0 2))");
ReferencedEnvelope bounds = new ReferencedEnvelope();
bounds.include(feature.getBounds());
bounds.expandToInclude(geom.getEnvelopeInternal());
store1.modifyFeatures(new Name[]{new NameImpl("geom")},
new Object[]{geom}, fidFilter);
// test that only the listener listening with the current transaction gets the event.
assertEquals(1, listener1.events.size());
assertEquals(0, listener2.events.size());
FeatureEvent event = listener1.getEvent(0);
assertEquals(bounds, event.getBounds());
assertEquals(FeatureEvent.Type.CHANGED, event.getType());
listener1.events.clear();
listener2.events.clear();
// test that rollback sends events to
// only the listener listening with the current transaction.
store1.getTransaction().rollback();
assertEquals(1, listener1.events.size());
assertEquals(0, listener2.events.size());
event = listener1.getEvent(0);
assertEquals(bounds, event.getBounds());
assertEquals(FeatureEvent.Type.ROLLBACK, event.getType());
listener1.events.clear();
listener2.events.clear();
//test remove
store1.removeFeatures(fidFilter);
assertEquals(1, listener1.events.size());
assertEquals(0, listener2.events.size());
event = listener1.getEvent(0);
assertEquals(feature.getBounds(), event.getBounds());
assertEquals(FeatureEvent.Type.REMOVED, event.getType());
listener1.events.clear();
listener2.events.clear();
// test that commit sends events to all listeners
// except the listener listening with the current transaction.
store1.getTransaction().commit();
assertEquals(0, listener1.events.size());
assertEquals(1, listener2.events.size());
event = listener2.getEvent(0);
assertEquals(feature.getBounds(), event.getBounds());
assertEquals(FeatureEvent.Type.COMMIT, event.getType());
listener1.events.clear();
listener2.events.clear();
// test add
store1.addFeatures(DataUtilities.collection(feature));
assertEquals(1, listener1.events.size());
event = listener1.getEvent(0);
assertEquals(feature.getBounds(), event.getBounds());
assertEquals(FeatureEvent.Type.ADDED, event.getType());
assertEquals(0, listener2.events.size());
listener1.events.clear();
listener2.events.clear();
// test that rollback sends events to
// only the listener listening with the current transaction.
store1.getTransaction().rollback();
assertEquals(1, listener1.events.size());
assertEquals(0, listener2.events.size());
event = listener1.getEvent(0);
assertEquals(FeatureEvent.Type.ROLLBACK, event.getType());
}
@Test
public void testBatchFeatureEvents() throws Exception {
DataStore store = new MockContentDataStore();
SimpleFeatureStore store1 = (SimpleFeatureStore) store.getFeatureSource(TYPENAME);
SimpleFeatureStore store2 = (SimpleFeatureStore) store.getFeatureSource(TYPENAME);
store1.setTransaction(defaultTransaction);
Listener listener1 = new Listener("one");
Listener listener2 = new Listener("two");
store1.addFeatureListener(listener1);
store2.addFeatureListener(listener2);
FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
final SimpleFeature feature0 = FEATURES.get(0);
final SimpleFeature feature1 = FEATURES.get(1);
Filter fidFilter0 = ff.id(feature0.getIdentifier());
Filter fidFilter1 = ff.id(feature1.getIdentifier());
//remove a feature
store1.removeFeatures(fidFilter0);
assertEquals(1, listener1.events.size());
assertEquals(0, listener2.events.size());
FeatureEvent event = listener1.getEvent(0);
assertEquals(feature0.getBounds(), event.getBounds());
assertEquals(FeatureEvent.Type.REMOVED, event.getType());
//remove another feature
store1.removeFeatures(fidFilter1);
assertEquals(2, listener1.events.size());
assertEquals(0, listener2.events.size());
event = listener1.getEvent(1);
assertEquals(feature1.getBounds(), event.getBounds());
assertEquals(FeatureEvent.Type.REMOVED, event.getType());
// commit the changes
store1.getTransaction().commit();
// test that multiple changes are contained within a single batch feature event
assertEquals(2, listener1.events.size());
assertEquals(1, listener2.events.size());
event = listener2.getEvent(0);
assertTrue(event instanceof BatchFeatureEvent);
ReferencedEnvelope bounds = new ReferencedEnvelope();
bounds.include(feature0.getBounds());
bounds.include(feature1.getBounds());
assertEquals(bounds, event.getBounds());
assertEquals(FeatureEvent.Type.COMMIT, event.getType());
}
}