0001: /*
0002: * GeoTools - OpenSource mapping toolkit
0003: * http://geotools.org
0004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation;
0009: * version 2.1 of the License.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: */
0016: package org.geotools.data.postgis;
0017:
0018: import java.io.IOException;
0019: import java.sql.Connection;
0020: import java.sql.Statement;
0021: import java.util.Arrays;
0022: import java.util.Collections;
0023: import java.util.HashSet;
0024: import java.util.List;
0025: import java.util.NoSuchElementException;
0026: import java.util.Set;
0027:
0028: import junit.framework.Test;
0029: import junit.framework.TestSuite;
0030: import junit.textui.ResultPrinter;
0031:
0032: import org.geotools.data.DataUtilities;
0033: import org.geotools.data.DefaultQuery;
0034: import org.geotools.data.DefaultTransaction;
0035: import org.geotools.data.FeatureLocking;
0036: import org.geotools.data.FeatureReader;
0037: import org.geotools.data.FeatureStore;
0038: import org.geotools.data.FeatureWriter;
0039: import org.geotools.data.Query;
0040: import org.geotools.data.Transaction;
0041: import org.geotools.data.VersioningFeatureSource;
0042: import org.geotools.factory.CommonFactoryFinder;
0043: import org.geotools.feature.AttributeType;
0044: import org.geotools.feature.Feature;
0045: import org.geotools.feature.FeatureCollection;
0046: import org.geotools.feature.FeatureIterator;
0047: import org.geotools.feature.FeatureType;
0048: import org.geotools.feature.IllegalAttributeException;
0049: import org.geotools.referencing.CRS;
0050: import org.opengis.filter.Filter;
0051: import org.opengis.filter.FilterFactory;
0052: import org.opengis.filter.Id;
0053: import org.opengis.filter.identity.FeatureId;
0054: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0055:
0056: import com.vividsolutions.jts.geom.Coordinate;
0057: import com.vividsolutions.jts.geom.Envelope;
0058:
0059: public class VersionedOperationsOnlineTest extends
0060: AbstractVersionedPostgisDataTestCase {
0061: FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
0062:
0063: public VersionedOperationsOnlineTest(String name) {
0064: super (name);
0065: }
0066:
0067: public void testTypeNames() throws IOException {
0068: VersionedPostgisDataStore ds = getDataStore();
0069: List typeNames = Arrays.asList(ds.getTypeNames());
0070: assertTrue(typeNames.contains("road"));
0071: assertFalse(typeNames.contains("road_wfc_view"));
0072: assertTrue(typeNames.contains("lake"));
0073: assertFalse(typeNames.contains("lake_wfc_view"));
0074: assertTrue(typeNames.contains("river"));
0075: assertFalse(typeNames.contains("rivel_wfc_view"));
0076: assertTrue(typeNames.contains("rail"));
0077: assertFalse(typeNames.contains("rail_wfc_view"));
0078: assertTrue(typeNames.contains("nopk"));
0079: assertFalse(typeNames.contains("nopk_wfc_view"));
0080: assertTrue(typeNames
0081: .contains(VersionedPostgisDataStore.TBL_CHANGESETS));
0082:
0083: assertFalse(typeNames
0084: .contains(VersionedPostgisDataStore.TBL_VERSIONEDTABLES));
0085: assertFalse(typeNames
0086: .contains(VersionedPostgisDataStore.TBL_TABLESCHANGED));
0087: }
0088:
0089: /**
0090: * Changesets is special, it's an internal table exposed for log access purposes, and it's not
0091: * writable
0092: */
0093: public void testChangesetFeatureType() throws IOException {
0094: VersionedPostgisDataStore ds = getDataStore();
0095: FeatureType ft = ds
0096: .getSchema(VersionedPostgisDataStore.TBL_CHANGESETS);
0097: assertNotNull(ft.getAttributeType("revision"));
0098: assertFalse(ds
0099: .getFeatureSource(VersionedPostgisDataStore.TBL_CHANGESETS) instanceof FeatureStore);
0100: }
0101:
0102: public void testVersionEnableDisableFeatureType()
0103: throws IOException {
0104: VersionedPostgisDataStore ds = getDataStore();
0105: FeatureType ft = ds.getSchema("road");
0106: assertFalse(ds.isVersioned("road"));
0107:
0108: // version
0109: ds.setVersioned("road", true, "gimbo",
0110: "Initial import of roads");
0111: assertTrue(ds.isVersioned("road"));
0112: assertEquals(ft, ds.getSchema("road"));
0113: if (ds.getFIDMapper("road").returnFIDColumnsAsAttributes())
0114: assertNotNull(ds.wrapped.getSchema("road")
0115: .getAttributeType("revision"));
0116: assertNotNull(ds.wrapped.getSchema("road").getAttributeType(
0117: "expired"));
0118: // check we don't see the versioned feature collection as a public type
0119: assertFalse(Arrays.asList(ds.getTypeNames()).contains(
0120: "road_vfc_view"));
0121:
0122: // check the versioned feature collection view is there
0123: FeatureType view = ds.wrapped.getSchema("road_vfc_view");
0124: AttributeType[] types = view.getAttributeTypes();
0125: assertEquals(ft.getAttributeCount() + 12, view
0126: .getAttributeCount());
0127: assertEquals("creationVersion", types[0].getLocalName());
0128: assertEquals("createdBy", types[1].getLocalName());
0129: assertEquals("creationDate", types[2].getLocalName());
0130: assertEquals("creationMessage", types[3].getLocalName());
0131: assertEquals("lastUpdateVersion", types[4].getLocalName());
0132: assertEquals("lastUpdatedBy", types[5].getLocalName());
0133: assertEquals("lastUpdateDate", types[6].getLocalName());
0134: assertEquals("lastUpdateMessage", types[7].getLocalName());
0135: // check the versioned feature collation is not visible outside of the verioning datastore
0136: try {
0137: ds.getSchema("road_vfc_view");
0138: fail("The versioning feature collection for road should not be visible as a standalone type");
0139: } catch (IOException e) {
0140: // ok
0141: }
0142:
0143: // un-version
0144: ds.setVersioned("road", false, "gimbo",
0145: "Versioning no more needed");
0146: assertFalse(ds.isVersioned("road"));
0147: assertEquals(ft, ds.getSchema("road"));
0148: assertNull(ds.wrapped.getSchema("road").getAttributeType(
0149: "revision"));
0150: assertNull(ds.wrapped.getSchema("road").getAttributeType(
0151: "expired"));
0152: try {
0153: ds.wrapped.getSchema("road_vfc_view");
0154: fail("The versioning view should not be there anymore");
0155: } catch (IOException e) {
0156: // ok
0157: }
0158: }
0159:
0160: public void testNonExistentTypes() throws IOException {
0161: VersionedPostgisDataStore ds = getDataStore();
0162: try {
0163: ds.isVersioned("blablabla");
0164: fail("Non existent type blablabla accepted anyways...");
0165: } catch (IOException e) {
0166: // ok, does not exist
0167: }
0168:
0169: ds.setVersioned("road", true, "gimbo",
0170: "Initial import of roads");
0171: try {
0172: ds.isVersioned(ds.getVFCViewName("road"));
0173: fail("Versioned feature collection view accepted as a legitimate type...");
0174: } catch (IOException e) {
0175: // ok, should not be accepted
0176: }
0177: }
0178:
0179: public void testVersionEnableChangeSets() throws IOException {
0180: VersionedPostgisDataStore ds = getDataStore();
0181: ds.getSchema(VersionedPostgisDataStore.TBL_CHANGESETS);
0182: assertFalse(ds.isVersioned("road"));
0183:
0184: // try version, should fail
0185: try {
0186: ds.setVersioned(VersionedPostgisDataStore.TBL_CHANGESETS,
0187: true, "gimbo", "Initial import of roads");
0188: fail("It should not be possible to version enable changesets");
0189: } catch (IOException e) {
0190: }
0191: }
0192:
0193: public void testVersionEnableEmptyTable() throws IOException {
0194: VersionedPostgisDataStore ds = getDataStore();
0195: assertFalse(ds.isVersioned("empty"));
0196:
0197: // try version enable, should go well despite the table being empty
0198: ds.setVersioned("empty", true, "gimbo",
0199: "Version enable deep space void");
0200: assertTrue(ds.isVersioned("empty"));
0201: }
0202:
0203: public void testVersionEnablePointTable() throws IOException {
0204: VersionedPostgisDataStore ds = getDataStore();
0205: assertFalse(ds.isVersioned("point"));
0206:
0207: // try version enable, should go well despite the single geom not making up a bbox
0208: // for the changeset
0209: ds.setVersioned("point", true, "gimbo",
0210: "Version enable a tiny damn point");
0211: assertTrue(ds.isVersioned("point"));
0212: }
0213:
0214: public void testGetFeatureReader() throws IOException,
0215: NoSuchElementException, Exception {
0216: VersionedPostgisDataStore ds = getDataStore();
0217:
0218: FeatureType originalFt = ds.getSchema("road");
0219: ds
0220: .setVersioned("road", true, "gimbo",
0221: "version enabling stuff");
0222: DefaultQuery q = new DefaultQuery("road");
0223: FeatureReader fr = ds.wrapped.getFeatureReader(q,
0224: Transaction.AUTO_COMMIT);
0225: while (fr.hasNext()) {
0226: Feature f = fr.next();
0227: assertEquals(new Long(1), (Long) f.getAttribute("revision"));
0228: assertEquals(new Long(Long.MAX_VALUE), (Long) f
0229: .getAttribute("expired"));
0230: }
0231: fr.close();
0232:
0233: // now insert by hand three revisions of first road and check we can
0234: // extract the good ones
0235: SqlTestUtils
0236: .execute(pool,
0237: "INSERT INTO CHANGESETS VALUES(2, 'gimbo', default, '', null)");
0238: SqlTestUtils
0239: .execute(pool,
0240: "INSERT INTO CHANGESETS VALUES(3, 'gimbo', default, '', null)");
0241: SqlTestUtils.execute(pool,
0242: "INSERT INTO ROAD SELECT FID, ID, GEOM, 'r1 rev 2', 2, 3, 2 "
0243: + "FROM ROAD WHERE ID = 1 AND EXPIRED = "
0244: + Long.MAX_VALUE);
0245: SqlTestUtils.execute(pool,
0246: "INSERT INTO ROAD SELECT FID, ID, GEOM, 'r1 rev 3', 3, "
0247: + Long.MAX_VALUE + ", 2 "
0248: + "FROM ROAD WHERE ID = 1 AND EXPIRED = "
0249: + Long.MAX_VALUE);
0250: SqlTestUtils.execute(pool,
0251: "UPDATE ROAD SET EXPIRED = 2 WHERE ID = 1 AND REVISION = 1 AND EXPIRED = "
0252: + Long.MAX_VALUE);
0253:
0254: // non versioned data store should return two more features now
0255: assertEquals(roadFeatures.length + 2, ds.wrapped
0256: .getFeatureSource("road").getCount(Query.ALL));
0257:
0258: // no revision info, use last
0259: Filter idFilter = ff.equals(ff.property("id"), ff.literal(1l));
0260: q = new DefaultQuery("road", idFilter);
0261: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0262: // make sure the type is the same as if we were working against a non
0263: // versioned datastore
0264: assertEquals(originalFt, fr.getFeatureType());
0265: assertTrue(fr.hasNext());
0266: Feature f = fr.next();
0267: assertEquals("road.rd1", f.getID());
0268: assertEquals("r1 rev 3", f.getAttribute("name"));
0269: assertFalse(fr.hasNext());
0270: fr.close();
0271:
0272: // now extract revision 1
0273: q = new DefaultQuery("road", idFilter);
0274: q.setVersion("1");
0275: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0276: assertTrue(fr.hasNext());
0277: f = fr.next();
0278: assertEquals("road.rd1", f.getID());
0279: assertEquals("r1", f.getAttribute("name"));
0280: assertFalse(fr.hasNext());
0281: fr.close();
0282:
0283: // and now extract revision 2
0284: q = new DefaultQuery("road", idFilter);
0285: q.setVersion("2");
0286: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0287: assertTrue(fr.hasNext());
0288: f = fr.next();
0289: assertEquals("road.rd1", f.getID());
0290: assertEquals("r1 rev 2", f.getAttribute("name"));
0291: assertFalse(fr.hasNext());
0292: fr.close();
0293:
0294: // now try the same with a fid filter
0295: Filter fidFilter = ff.id(Collections.singleton(ff
0296: .featureId("road.rd1")));
0297: q = new DefaultQuery("road", fidFilter);
0298:
0299: // fid and last revision
0300: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0301: assertTrue(fr.hasNext());
0302: f = fr.next();
0303: assertEquals("road.rd1", f.getID());
0304: assertEquals("r1 rev 3", f.getAttribute("name"));
0305: assertFalse(fr.hasNext());
0306: fr.close();
0307:
0308: // fid and specific revision
0309: q = new DefaultQuery("road", fidFilter);
0310: q.setVersion("2");
0311: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0312: assertTrue(fr.hasNext());
0313: f = fr.next();
0314: assertEquals("road.rd1", f.getID());
0315: assertEquals("r1 rev 2", f.getAttribute("name"));
0316: assertFalse(fr.hasNext());
0317: fr.close();
0318: }
0319:
0320: public void testFidFilter() throws IOException,
0321: NoSuchElementException, IllegalAttributeException {
0322: VersionedPostgisDataStore ds = getDataStore();
0323:
0324: // check querying with fids out of the expected format does not break
0325: // the datastore
0326: Filter f = ff
0327: .id(new HashSet(Arrays.asList(new FeatureId[] {
0328: ff.featureId("road.rd1"),
0329: ff.featureId("strangeId") })));
0330: Query q = new DefaultQuery("road", f);
0331: FeatureReader fr = ds.getFeatureReader(q,
0332: Transaction.AUTO_COMMIT);
0333: assertTrue(fr.hasNext());
0334: fr.next();
0335: assertFalse(fr.hasNext());
0336: fr.close();
0337:
0338: // check querying with fids out of the expected format does not break
0339: // the datastore
0340: // this one should turn the filter into a Filter.EXCLUDE thing
0341: f = ff.id(new HashSet(Arrays.asList(new FeatureId[] { ff
0342: .featureId("xyz:?strangeId") })));
0343: q = new DefaultQuery("road", f);
0344: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0345: assertFalse(fr.hasNext());
0346: fr.close();
0347:
0348: // check querying with fids out of the expected format does not break
0349: // the datastore
0350: // this one was putting the filter splitter in dismay
0351: f = ff.id(new HashSet(Arrays.asList(new FeatureId[] { ff
0352: .featureId("xyz:?strangeId") })));
0353: f = ff.and(f, ff.bbox("geom", -100, -100, 100, 100, null));
0354: q = new DefaultQuery("road", f);
0355: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0356: assertFalse(fr.hasNext());
0357: fr.close();
0358: }
0359:
0360: public void testGetFeatureWriter() throws IOException,
0361: NoSuchElementException, Exception {
0362: VersionedPostgisDataStore ds = getDataStore();
0363: Envelope originalBounds = ds.wrapped.getFeatureSource("road")
0364: .getBounds();
0365:
0366: // version enable road
0367: FeatureType originalFt = ds.getSchema("road");
0368: ds
0369: .setVersioned("road", true, "gimbo",
0370: "version enabling stuff");
0371:
0372: // build a filter to extract just road 1
0373: Filter filter = ff.id(Collections.singleton(ff
0374: .featureId("road.rd1")));
0375:
0376: // now write one revision
0377: Transaction t = createTransaction("gimbo", "first change");
0378: FeatureWriter fw = ds.getFeatureWriter("road", filter, t);
0379: assertTrue(fw.hasNext());
0380: Feature f = fw.next();
0381: f.setAttribute("name", "r1 rev 2");
0382: fw.write();
0383: fw.close();
0384: t.commit();
0385: assertEquals(new Long(2), t
0386: .getProperty(VersionedPostgisDataStore.REVISION));
0387: assertEquals("2", t
0388: .getProperty(VersionedPostgisDataStore.VERSION));
0389: t.close();
0390:
0391: // write another
0392: t = createTransaction("gimbo", "second change");
0393: fw = ds.getFeatureWriter("road", filter, t);
0394: assertTrue(fw.hasNext());
0395: f = fw.next();
0396: f.setAttribute("name", "r1 rev 3");
0397: fw.write();
0398: fw.close();
0399: t.commit();
0400: t.close();
0401:
0402: // check we have the rigth changesets in the database
0403: DefaultQuery q = new DefaultQuery(
0404: VersionedPostgisDataStore.TBL_CHANGESETS);
0405: t = new DefaultTransaction();
0406: FeatureReader fr = ds.getFeatureReader(q, t);
0407: // ... ah, would very much like to sort on revision...
0408: // ... first revision, import
0409: assertTrue(fr.hasNext());
0410: f = fr.next();
0411: assertEquals(new Long(1), f.getAttribute("revision"));
0412: // TODO : get revision back among the attributes
0413: // assertEquals(new Long(1), f.getAttribute("revision"));
0414: assertEquals(originalBounds, f.getDefaultGeometry()
0415: .getEnvelopeInternal());
0416: // ... first change
0417: assertTrue(fr.hasNext());
0418: f = fr.next();
0419: assertEquals(new Long(2), f.getAttribute("revision"));
0420: assertEquals("first change", f.getAttribute("message"));
0421: assertEquals(
0422: roadFeatures[0].getDefaultGeometry().getEnvelope(), f
0423: .getDefaultGeometry().getEnvelope());
0424: // ... second change
0425: assertTrue(fr.hasNext());
0426: f = fr.next();
0427: assertEquals(new Long(3), f.getAttribute("revision"));
0428: assertEquals("second change", f.getAttribute("message"));
0429: assertEquals(
0430: roadFeatures[0].getDefaultGeometry().getEnvelope(), f
0431: .getDefaultGeometry().getEnvelope());
0432: // finish
0433: assertFalse(fr.hasNext());
0434: fr.close();
0435: t.close();
0436:
0437: // no revision info, use last
0438: Filter idFilter = ff.equals(ff.property("id"), ff.literal(1l));
0439: q = new DefaultQuery("road", idFilter);
0440: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0441: // make sure the type is the same as if we were working against a non
0442: // versioned datastore
0443: assertEquals(originalFt, fr.getFeatureType());
0444: assertTrue(fr.hasNext());
0445: f = fr.next();
0446: assertEquals("r1 rev 3", f.getAttribute("name"));
0447: assertFalse(fr.hasNext());
0448: fr.close();
0449:
0450: // now extract revision 1
0451: q = new DefaultQuery("road", idFilter);
0452: q.setVersion("1");
0453: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0454: assertTrue(fr.hasNext());
0455: f = fr.next();
0456: assertEquals("r1", f.getAttribute("name"));
0457: assertFalse(fr.hasNext());
0458: fr.close();
0459:
0460: // and now extract revision 2
0461: q = new DefaultQuery("road", idFilter);
0462: q.setVersion("2");
0463: fr = ds.getFeatureReader(q, Transaction.AUTO_COMMIT);
0464: assertTrue(fr.hasNext());
0465: f = fr.next();
0466: assertEquals("r1 rev 2", f.getAttribute("name"));
0467: assertFalse(fr.hasNext());
0468: fr.close();
0469: }
0470:
0471: public void testAppendFeatures() throws IOException,
0472: IllegalAttributeException {
0473: VersionedPostgisDataStore ds = getDataStore();
0474:
0475: // version enable road and river
0476: ds
0477: .setVersioned("road", true, "gimbo",
0478: "version enabling roads");
0479: ds.setVersioned("river", true, "gimbo",
0480: "version enabling river");
0481:
0482: // create a transaction and append some features to both feature types
0483: Transaction t = createTransaction("mambo",
0484: "Today I feel like adding fetures, yeah");
0485: FeatureWriter fw = ds.getFeatureWriterAppend("road", t);
0486: // ... new road
0487: Feature f = fw.next();
0488: f.setAttribute(0, new Integer(4));
0489: f.setAttribute(1, line(new int[] { 3, 3, 4, 4, 5, 10 }));
0490: f.setAttribute(2, "r4");
0491: fw.write();
0492: String rd4id = f.getID();
0493: fw.close();
0494: // ... new river
0495: fw = ds.getFeatureWriterAppend("river", t);
0496: f = fw.next();
0497: f.setAttribute(0, new Integer(4));
0498: f.setAttribute(1, lines(new int[][] { { 0, 0, 1, 10 } }));
0499: f.setAttribute(2, "rv4");
0500: f.setAttribute(3, new Double(6.5));
0501: fw.write();
0502: String rv4id = f.getID();
0503: fw.close();
0504: // ... end
0505: t.commit();
0506:
0507: // check features are there
0508: // ... roads
0509: DefaultQuery q = new DefaultQuery("road", ff.id(Collections
0510: .singleton(ff.featureId(rd4id))));
0511: FeatureReader fr = ds.getFeatureReader(q, t);
0512: assertTrue(fr.hasNext());
0513: fr.close();
0514: // ... rivers
0515: q = new DefaultQuery("river", ff.id(Collections.singleton(ff
0516: .featureId(rv4id))));
0517: fr = ds.getFeatureReader(q, t);
0518: assertTrue(fr.hasNext());
0519: fr.close();
0520:
0521: // ok, now check we registered the modification to both tables in the
0522: // same revision
0523: assertEquals(3, ds.getLastRevision());
0524: List types = Arrays
0525: .asList(ds.getModifiedFeatureTypes("2", "3"));
0526: assertEquals(2, types.size());
0527: assertTrue(types.contains("river"));
0528: assertTrue(types.contains("road"));
0529:
0530: // remember to close down the transaction
0531: t.close();
0532: }
0533:
0534: /**
0535: * The datastore used to choke on single point changes because the change bbox would be an
0536: * invalid polygon. Plus the feature collection seems to ignore the version set in the query
0537: * used to gather it
0538: *
0539: * @throws Exception
0540: */
0541: public void testPointChange() throws Exception {
0542: VersionedPostgisDataStore ds = getDataStore();
0543:
0544: // version enable tree
0545: ds.setVersioned("tree", true, "gimbo", "versioning trees");
0546:
0547: // now create one feature
0548: FeatureWriter fw = ds.getFeatureWriterAppend("tree",
0549: Transaction.AUTO_COMMIT);
0550: assertFalse(fw.hasNext());
0551: Feature f = fw.next();
0552: f.setAttribute(0, gf.createPoint(new Coordinate(50, 50)));
0553: f.setAttribute(1, "NewTreeOnTheBlock");
0554: fw.write();
0555: fw.close();
0556: }
0557:
0558: /**
0559: * The datastore used to choke on single point changes because the change bbox would be an
0560: * invalid polygon. Plus the feature collection seems to ignore the version set in the query
0561: * used to gather it
0562: *
0563: * @throws Exception
0564: */
0565: public void testFeatureSourceBounds() throws Exception {
0566: VersionedPostgisDataStore ds = getDataStore();
0567:
0568: // version enable tree
0569: ds.setVersioned("tree", true, "gimbo", "versioning trees");
0570:
0571: // now create one feature
0572: FeatureWriter fw = ds.getFeatureWriter("tree",
0573: Transaction.AUTO_COMMIT);
0574: assertTrue(fw.hasNext());
0575: Feature f = fw.next();
0576: Envelope oldBounds = f.getBounds();
0577: f.setAttribute(0, gf.createPoint(new Coordinate(50, 50)));
0578: fw.write();
0579: fw.close();
0580:
0581: // try to gather an old snapshot and check the bounds are really the old
0582: // ones
0583: DefaultQuery q = new DefaultQuery();
0584: q.setVersion("1");
0585: Envelope e = ds.getFeatureSource("tree").getBounds(q);
0586: assertEquals(oldBounds, e);
0587: }
0588:
0589: public void testDeleteFeatures() throws IOException,
0590: NoSuchElementException, IllegalAttributeException {
0591: VersionedPostgisDataStore ds = getDataStore();
0592:
0593: // version enable road
0594: ds
0595: .setVersioned("road", true, "gimbo",
0596: "version enabling stuff");
0597:
0598: // build a filter to extract just road 1
0599: Filter filter = ff.id(Collections.singleton(ff
0600: .featureId("road.rd1")));
0601:
0602: // now delete one feature
0603: Transaction t = createTransaction("gimbo", "first change");
0604: FeatureWriter fw = ds.getFeatureWriter("road", filter, t);
0605: assertTrue(fw.hasNext());
0606: fw.next();
0607: fw.remove();
0608: fw.close();
0609: t.commit();
0610: t.close();
0611:
0612: // and now see if it's still there
0613: FeatureReader fr = ds.getFeatureReader(
0614: new DefaultQuery("road"), Transaction.AUTO_COMMIT);
0615: while (fr.hasNext())
0616: assertFalse(fr.next().getID().equals("road.rd1"));
0617: fr.close();
0618: }
0619:
0620: /**
0621: * Versioned datastore broke if the same feature got updated twice in the same transaction
0622: * (since it tried to create a new record at revions x, then expired it, and created another
0623: * again at revision x).
0624: *
0625: * @throws Exception
0626: *
0627: */
0628: public void testDoubleUpdate() throws Exception {
0629: VersionedPostgisDataStore ds = getDataStore();
0630:
0631: // version enable trees
0632: ds
0633: .setVersioned("tree", true, "udig",
0634: "I like to doubly update things in the same transaction :-)");
0635:
0636: // build a filter to extract just road 1
0637: Filter filter = ff.id(Collections.singleton(ff
0638: .featureId("tree.1")));
0639:
0640: // setup a transaction
0641: Transaction t = createTransaction("gimbo", "double update");
0642: FeatureStore store = (FeatureStore) ds.getFeatureSource("tree");
0643: FeatureType treeSchema = ds.getSchema("tree");
0644: store.setTransaction(t);
0645: assertEquals(1, store.getFeatures(filter).size());
0646: store.modifyFeatures(treeSchema.getAttributeType("name"),
0647: "update1", filter);
0648: store.modifyFeatures(treeSchema.getAttributeType("name"),
0649: "update2", filter);
0650: t.commit();
0651:
0652: // make sure the second update is the one that went in
0653: FeatureCollection fc = store.getFeatures(filter);
0654: FeatureIterator fi = fc.features();
0655: assertTrue(fi.hasNext());
0656: Feature f = fi.next();
0657: assertEquals("update2", f.getAttribute("name"));
0658: assertFalse(fi.hasNext());
0659: fi.close();
0660: t.close();
0661: }
0662:
0663: /**
0664: * Check insert/delete in the same transaction works
0665: *
0666: * @throws Exception
0667: *
0668: */
0669: public void testInsertDelete() throws Exception {
0670: VersionedPostgisDataStore ds = getDataStore();
0671:
0672: // version enable trees
0673: ds.setVersioned("tree", true, "gimbo",
0674: "What do you want, I'm undecided...");
0675:
0676: // create a new feature
0677: Feature tree = treeType.create(new Object[] {
0678: gf.createPoint(new Coordinate(7, 7)), "SmallPine" },
0679: "tree.tr2");
0680:
0681: // setup a transaction
0682: Transaction t = createTransaction("gimbo", "double update");
0683: FeatureStore store = (FeatureStore) ds.getFeatureSource("tree");
0684: store.setTransaction(t);
0685: Set ids = store.addFeatures(DataUtilities.collection(tree));
0686: Filter filter = ff.id(Collections.singleton(ff
0687: .featureId((String) ids.iterator().next())));
0688: store.removeFeatures(filter);
0689: t.commit();
0690:
0691: // check it's not there
0692: assertEquals(0, store.getFeatures(filter).size());
0693: t.close();
0694: }
0695:
0696: /**
0697: * Same as double update, but for the insert/update case
0698: *
0699: * @throws Exception
0700: *
0701: */
0702: public void testInsertUpdate() throws Exception {
0703: VersionedPostgisDataStore ds = getDataStore();
0704:
0705: // version enable trees
0706: ds.setVersioned("tree", true, "gimbo",
0707: "What do you want, I'm undecided...");
0708:
0709: // create a new feature
0710: Feature tree = treeType.create(new Object[] {
0711: gf.createPoint(new Coordinate(7, 7)), "SmallPine" },
0712: "tree.tr2");
0713:
0714: // setup a transaction
0715: Transaction t = createTransaction("gimbo", "double update");
0716: FeatureType treeSchema = ds.getSchema("tree");
0717: FeatureStore store = (FeatureStore) ds.getFeatureSource("tree");
0718: store.setTransaction(t);
0719: Set ids = store.addFeatures(DataUtilities.collection(tree));
0720: Filter filter = ff.id(Collections.singleton(ff
0721: .featureId((String) ids.iterator().next())));
0722: assertEquals(1, store.getFeatures(filter).size());
0723: store.modifyFeatures(treeSchema.getAttributeType("name"),
0724: "update1", filter);
0725: t.commit();
0726: t.close();
0727: }
0728:
0729: public void testSerialIdWriting() throws IOException,
0730: IllegalArgumentException, IllegalAttributeException {
0731: VersionedPostgisDataStore ds = getDataStore();
0732: ds
0733: .setVersioned("rail", true, "mambo",
0734: "Version enabling rails");
0735:
0736: Transaction t = createTransaction("serial",
0737: "Feature modification");
0738: FeatureWriter fw = ds.getFeatureWriter("rail", Filter.INCLUDE,
0739: t);
0740: assertTrue(fw.hasNext());
0741: Feature f = fw.next();
0742: f.setDefaultGeometry(line(new int[] { 0, 0, -10, -10 }));
0743: fw.write();
0744: fw.close();
0745: t.commit();
0746:
0747: fw = ds.getFeatureWriterAppend("rail", t);
0748: f = fw.next();
0749: f.setDefaultGeometry(line(new int[] { -10, -10, -20, -10 }));
0750: fw.write();
0751: assertEquals("rail.2", f.getID());
0752: fw.close();
0753: t.commit();
0754:
0755: fw = ds.getFeatureWriter("rail", ff.id(Collections.singleton(ff
0756: .featureId("rail.1"))), t);
0757: assertTrue(fw.hasNext());
0758: f = fw.next();
0759: fw.remove();
0760: fw.close();
0761: t.commit();
0762: t.close();
0763: }
0764:
0765: public void testPlainModifiedIds() throws IOException,
0766: IllegalAttributeException {
0767: VersionedPostgisDataStore ds = getDataStore();
0768: String newId = buildRiverHistory();
0769:
0770: // check modified feature types are the proper ones
0771: // full history
0772: String[] modifiedTypes = ds.getModifiedFeatureTypes("1", null);
0773: assertEquals(1, modifiedTypes.length);
0774: assertEquals("river", modifiedTypes[0]);
0775:
0776: // get features modified in first revisions, without filters
0777: Transaction ac = Transaction.AUTO_COMMIT;
0778: // ... all history
0779: ModifiedFeatureIds mfids = ds.getModifiedFeatureFIDs("river",
0780: "1", "5", Filter.INCLUDE, null, ac);
0781: assertEquals(1, mfids.getCreated().size());
0782: assertEquals(1, mfids.getDeleted().size());
0783: assertEquals(1, mfids.getModified().size());
0784: assertTrue(mfids.getCreated().contains(newId));
0785: assertTrue(mfids.getDeleted().contains("river.rv2"));
0786: assertTrue(mfids.getModified().contains("river.rv1"));
0787: // ... just first modification
0788: mfids = ds.getModifiedFeatureFIDs("river", "1", "2",
0789: Filter.INCLUDE, null, ac);
0790: assertEquals(0, mfids.getCreated().size());
0791: assertEquals(0, mfids.getDeleted().size());
0792: assertEquals(2, mfids.getModified().size());
0793: assertTrue(mfids.getModified().contains("river.rv1"));
0794: assertTrue(mfids.getModified().contains("river.rv2"));
0795: // ... just second one
0796: mfids = ds.getModifiedFeatureFIDs("river", "2", "3",
0797: Filter.INCLUDE, null, ac);
0798: assertEquals(0, mfids.getCreated().size());
0799: assertEquals(0, mfids.getDeleted().size());
0800: assertEquals(1, mfids.getModified().size());
0801: assertTrue(mfids.getModified().contains("river.rv2"));
0802: // ... just creation and deletion
0803: mfids = ds.getModifiedFeatureFIDs("river", "3", "5",
0804: Filter.INCLUDE, null, ac);
0805: assertEquals(1, mfids.getCreated().size());
0806: assertEquals(1, mfids.getDeleted().size());
0807: assertEquals(0, mfids.getModified().size());
0808: assertTrue(mfids.getCreated().contains(newId));
0809: assertTrue(mfids.getDeleted().contains("river.rv2"));
0810: // ... a non existent one
0811: mfids = ds.getModifiedFeatureFIDs("river", "10", "11",
0812: Filter.INCLUDE, null, ac);
0813: assertEquals(0, mfids.getCreated().size());
0814: assertEquals(0, mfids.getDeleted().size());
0815: assertEquals(0, mfids.getModified().size());
0816:
0817: // now check with some filters too
0818: // ... a fid one
0819: Filter fidFilter = ff.id(Collections.singleton(ff
0820: .featureId("river.rv1")));
0821: mfids = ds.getModifiedFeatureFIDs("river", "1", "3", fidFilter,
0822: null, ac);
0823: assertEquals(0, mfids.getCreated().size());
0824: assertEquals(0, mfids.getDeleted().size());
0825: assertEquals(1, mfids.getModified().size());
0826: assertTrue(mfids.getModified().contains("river.rv1"));
0827: // ... a bbox one
0828: Filter bboxFilter = ff.bbox("geom", 100, 100, 300, 300, null);
0829: mfids = ds.getModifiedFeatureFIDs("river", "1", "3",
0830: bboxFilter, null, ac);
0831: assertEquals(0, mfids.getCreated().size());
0832: assertEquals(0, mfids.getDeleted().size());
0833: assertEquals(1, mfids.getModified().size());
0834: assertTrue(mfids.getModified().contains("river.rv2"));
0835: // ... a non encodable one, matching
0836: Filter roundedFlowFilter = ff.equals(ff.function("ceil", ff
0837: .property("flow")), ff.literal(10));
0838: mfids = ds.getModifiedFeatureFIDs("river", "1", "3",
0839: roundedFlowFilter, null, ac);
0840: assertEquals(0, mfids.getCreated().size());
0841: assertEquals(0, mfids.getDeleted().size());
0842: assertEquals(1, mfids.getModified().size());
0843: assertTrue(mfids.getModified().contains("river.rv1"));
0844: // ... same filter, but feature not modified in those revisions
0845: mfids = ds.getModifiedFeatureFIDs("river", "2", "3",
0846: roundedFlowFilter, null, ac);
0847: assertEquals(0, mfids.getCreated().size());
0848: assertEquals(0, mfids.getDeleted().size());
0849: assertEquals(0, mfids.getModified().size());
0850: // ... a non encodable one, not matching
0851: Filter roundedFlowFilter2 = ff.equals(ff.function("ceil", ff
0852: .property("flow")), ff.literal(11));
0853: mfids = ds.getModifiedFeatureFIDs("river", "1", "3",
0854: roundedFlowFilter2, null, ac);
0855: assertEquals(0, mfids.getCreated().size());
0856: assertEquals(0, mfids.getDeleted().size());
0857: assertEquals(0, mfids.getModified().size());
0858: }
0859:
0860: public void testUserModifiedIds() throws IOException,
0861: IllegalAttributeException {
0862: VersionedPostgisDataStore ds = getDataStore();
0863: String newId = buildRiverHistory();
0864:
0865: // check modified feature types are the proper ones
0866: // full history
0867: String[] modifiedTypes = ds.getModifiedFeatureTypes("1", null);
0868: assertEquals(1, modifiedTypes.length);
0869: assertEquals("river", modifiedTypes[0]);
0870:
0871: // get features modified in first revisions, without filters
0872: Transaction ac = Transaction.AUTO_COMMIT;
0873: // ... all history, all users
0874: ModifiedFeatureIds mfids = ds.getModifiedFeatureFIDs("river",
0875: "1", "5", Filter.INCLUDE, new String[] { "lamb",
0876: "trout" }, ac);
0877: assertEquals(1, mfids.getCreated().size());
0878: assertEquals(1, mfids.getDeleted().size());
0879: assertEquals(1, mfids.getModified().size());
0880: // ... just first modification, but with the wrong user
0881: mfids = ds.getModifiedFeatureFIDs("river", "1", "2",
0882: Filter.INCLUDE, new String[] { "trout" }, ac);
0883: assertEquals(0, mfids.getCreated().size());
0884: assertEquals(0, mfids.getDeleted().size());
0885: assertEquals(0, mfids.getModified().size());
0886: // ... again the first modification, right user this time
0887: mfids = ds.getModifiedFeatureFIDs("river", "1", "2",
0888: Filter.INCLUDE, new String[] { "lamb" }, ac);
0889: assertEquals(0, mfids.getCreated().size());
0890: assertEquals(0, mfids.getDeleted().size());
0891: assertEquals(2, mfids.getModified().size());
0892: // ... let's see what trout did between 1 and 4
0893: mfids = ds.getModifiedFeatureFIDs("river", "1", "4",
0894: Filter.INCLUDE, new String[] { "trout" }, ac);
0895: assertEquals(0, mfids.getCreated().size());
0896: assertEquals(0, mfids.getDeleted().size());
0897: assertEquals(1, mfids.getModified().size());
0898: assertTrue(mfids.getModified().contains("river.rv2"));
0899: }
0900:
0901: public void testModifiedIdsUnversioned() throws IOException,
0902: IllegalAttributeException {
0903: VersionedPostgisDataStore ds = getDataStore();
0904:
0905: // check we get no modifications out of an unversioned feature type
0906: ModifiedFeatureIds mfids = ds
0907: .getModifiedFeatureFIDs("river", "1", "5",
0908: Filter.INCLUDE, null, Transaction.AUTO_COMMIT);
0909: assertTrue(mfids.getCreated().isEmpty());
0910: assertTrue(mfids.getDeleted().isEmpty());
0911: assertTrue(mfids.getModified().isEmpty());
0912: }
0913:
0914: public void testRollbackDeleted() throws IOException,
0915: IllegalAttributeException {
0916: VersionedPostgisDataStore ds = getDataStore();
0917: buildRiverHistory();
0918:
0919: Filter rv2Filter = ff.id(Collections.singleton(ff
0920: .featureId("river.rv2")));
0921: FeatureReader fr = ds.getFeatureReader(new DefaultQuery(
0922: "river", rv2Filter), Transaction.AUTO_COMMIT);
0923: assertFalse(fr.hasNext());
0924: fr.close();
0925:
0926: // try to rollback to revision 4, that is, rollback last deletion
0927: Transaction t = createTransaction("Mambo",
0928: "Gimbo, what did you do? "
0929: + "Now I have to rollback your changes!");
0930: VersionedPostgisFeatureStore fs = (VersionedPostgisFeatureStore) ds
0931: .getFeatureSource("river");
0932: fs.setTransaction(t);
0933: fs.rollback("4", Filter.INCLUDE, null);
0934: t.commit();
0935:
0936: // now check rv2 is again there
0937: fr = ds.getFeatureReader(new DefaultQuery("river", rv2Filter),
0938: Transaction.AUTO_COMMIT);
0939: assertTrue(fr.hasNext());
0940: fr.close();
0941: assertEquals(3, fs.getFeatures(Filter.INCLUDE).size());
0942: t.close();
0943: }
0944:
0945: public void testRollbackCreatedDeleted() throws IOException,
0946: IllegalAttributeException {
0947: VersionedPostgisDataStore ds = getDataStore();
0948: String newId = buildRiverHistory();
0949:
0950: // try to rollback to revision 3, that is, rollback last deletion and
0951: // creation
0952: Transaction t = createTransaction("Mambo",
0953: "Gimbo, what did you do? "
0954: + "Now I have to rollback your changes!");
0955: VersionedPostgisFeatureStore fs = (VersionedPostgisFeatureStore) ds
0956: .getFeatureSource("river");
0957: fs.setTransaction(t);
0958: fs.rollback("3", Filter.INCLUDE, null);
0959: t.commit();
0960:
0961: // now check rv2 is again there
0962: Filter rv2Filter = ff.id(Collections.singleton(ff
0963: .featureId("river.rv2")));
0964: Filter newFilter = ff.id(Collections.singleton(ff
0965: .featureId(newId)));
0966: FeatureReader fr = ds.getFeatureReader(new DefaultQuery(
0967: "river", rv2Filter), Transaction.AUTO_COMMIT);
0968: assertTrue(fr.hasNext());
0969: fr.close();
0970: fr = ds.getFeatureReader(new DefaultQuery("river", newFilter),
0971: Transaction.AUTO_COMMIT);
0972: assertFalse(fr.hasNext());
0973: fr.close();
0974: assertEquals(2, fs.getFeatures(Filter.INCLUDE).size());
0975:
0976: t.close();
0977: }
0978:
0979: public void testRollbackAll() throws IOException,
0980: IllegalAttributeException {
0981: VersionedPostgisDataStore ds = getDataStore();
0982: buildRiverHistory();
0983:
0984: // try to rollback to revision 3, that is, rollback last deletion and
0985: // creation
0986: Transaction t = createTransaction("Mambo",
0987: "Gimbo, what did you do? "
0988: + "Now I have to rollback your changes!");
0989: VersionedPostgisFeatureStore fs = (VersionedPostgisFeatureStore) ds
0990: .getFeatureSource("river");
0991: fs.setTransaction(t);
0992: fs.rollback("1", Filter.INCLUDE, null);
0993: t.commit();
0994:
0995: // now check river features are just like at the beginning
0996: FeatureCollection fc = fs.getFeatures();
0997: assertEquals(riverFeatures.length, fc.size());
0998: for (int i = 0; i < riverFeatures.length; i++) {
0999: assertTrue(fc.contains(riverFeatures[i]));
1000: }
1001: t.close();
1002: }
1003:
1004: public void testRollbackUserChanges() throws IOException,
1005: IllegalAttributeException {
1006: VersionedPostgisDataStore ds = getDataStore();
1007: buildRiverHistory();
1008:
1009: // try to rollback to revision 3, that is, rollback last deletion and
1010: // creation
1011: Transaction t = createTransaction("Lamb",
1012: "Trout, what did you do? "
1013: + "Now I have to rollback your changes!");
1014: VersionedPostgisFeatureStore fs = (VersionedPostgisFeatureStore) ds
1015: .getFeatureSource("river");
1016: fs.setTransaction(t);
1017: fs.rollback("1", Filter.INCLUDE, new String[] { "trout" });
1018: t.commit();
1019:
1020: // now check that rv2 is again there an equal to the original, rv3 has not rolled back
1021: // and rv1 is still modified
1022: FeatureCollection fc = fs.getFeatures();
1023: assertEquals(riverFeatures.length + 1, fc.size());
1024: assertTrue(fc.contains(riverFeatures[1]));
1025: FeatureIterator fi = fc.features();
1026: while (fi.hasNext()) {
1027: Feature f = fi.next();
1028: if (f.getID().equals("river.rv1"))
1029: assertFalse(f.equals(riverFeatures[1]));
1030: else if (f.getID().equals("river.rv2"))
1031: assertEquals(riverFeatures[1], f);
1032: else
1033: assertEquals(new Integer(3), f.getAttribute("id"));
1034: }
1035: fi.close();
1036: t.close();
1037: }
1038:
1039: public void testVolatilePk() throws IOException,
1040: IllegalAttributeException {
1041: VersionedPostgisDataStore ds = getDataStore();
1042:
1043: assertTrue(ds.getFeatureSource("river") instanceof FeatureLocking);
1044: assertFalse(ds.getFeatureSource("nopk") instanceof FeatureLocking);
1045: }
1046:
1047: public void testFeatureStoreUnversioned() throws IOException,
1048: IllegalAttributeException {
1049: VersionedPostgisDataStore ds = getDataStore();
1050:
1051: // try to get a feature store for an unversioned type, it should be a
1052: // plain feature store
1053: // not the versioned one
1054: FeatureStore fs = (FeatureStore) ds.getFeatureSource("river");
1055: assertFalse(fs instanceof VersionedPostgisFeatureStore);
1056: }
1057:
1058: public void testLog() throws IOException, IllegalAttributeException {
1059: VersionedPostgisDataStore ds = getDataStore();
1060: String newId = buildRiverHistory();
1061: VersionedPostgisFeatureStore fs = (VersionedPostgisFeatureStore) ds
1062: .getFeatureSource("river");
1063:
1064: // get log only for newly created features
1065: Filter newIdFilter = ff.id(Collections.singleton(ff
1066: .featureId(newId)));
1067: FeatureCollection fc = fs.getLog("1", "5", newIdFilter, null,
1068: -1);
1069: assertEquals(1, fc.size());
1070: FeatureIterator it = fc.features();
1071: Feature f = it.next();
1072: assertEquals("changesets.4", f.getID());
1073: assertEquals("lamb", f.getAttribute("author"));
1074: assertEquals("third change", f.getAttribute("message"));
1075: it.close();
1076:
1077: // get log for rv2 (most modified)
1078: Filter rv2IdFilter = ff.id(Collections.singleton(ff
1079: .featureId("river.rv2")));
1080: fc = fs.getLog("1", "5", rv2IdFilter, null, -1);
1081: assertEquals(3, fc.size());
1082: it = fc.features();
1083: f = it.next();
1084: assertEquals(new Long(5), f.getAttribute("revision"));
1085: assertEquals("trout", f.getAttribute("author"));
1086: assertEquals("fourth change", f.getAttribute("message"));
1087: f = it.next();
1088: assertEquals(new Long(3), f.getAttribute("revision"));
1089: assertEquals("trout", f.getAttribute("author"));
1090: assertEquals("second change", f.getAttribute("message"));
1091: f = it.next();
1092: assertEquals(new Long(2), f.getAttribute("revision"));
1093: assertEquals("lamb", f.getAttribute("author"));
1094: assertEquals("first change", f.getAttribute("message"));
1095: it.close();
1096:
1097: // get log for rv1
1098: Filter rv1IdFilter = ff.id(Collections.singleton(ff
1099: .featureId("river.rv1")));
1100: fc = fs.getLog("1", "5", rv1IdFilter, null, -1);
1101: assertEquals(1, fc.size());
1102: it = fc.features();
1103: f = it.next();
1104: assertEquals("changesets.2", f.getID());
1105: assertEquals("lamb", f.getAttribute("author"));
1106: assertEquals("first change", f.getAttribute("message"));
1107: it.close();
1108:
1109: // make sure the symbolic names for feature versions do work
1110: fc = fs.getLog("FIRST", "LAST", Filter.INCLUDE, null, -1);
1111: assertEquals(4, fc.size());
1112:
1113: // make sure the old way to specify the current version works too
1114: fc = fs.getLog("FIRST", "CURRENT", Filter.INCLUDE, null, -1);
1115: assertEquals(4, fc.size());
1116:
1117: // make sure maxRows works
1118: fc = fs.getLog("FIRST", "LAST", Filter.INCLUDE, null, 1);
1119: assertEquals(1, fc.size());
1120:
1121: // try out with an inverted sequence and see if we get an inverted log order
1122: fc = fs.getLog("LAST", "FIRST", Filter.INCLUDE, null, -1);
1123: assertEquals(4, fc.size());
1124: it = fc.features();
1125: f = it.next();
1126: long r1 = ((Long) f.getAttribute("revision")).longValue();
1127: f = it.next();
1128: long r2 = ((Long) f.getAttribute("revision")).longValue();
1129: assertTrue(r1 < r2);
1130: it.close();
1131: }
1132:
1133: public void testDiff() throws IOException,
1134: IllegalAttributeException {
1135: VersionedPostgisDataStore ds = getDataStore();
1136: buildRiverHistory();
1137: VersionedPostgisFeatureStore fs = (VersionedPostgisFeatureStore) ds
1138: .getFeatureSource("river");
1139:
1140: // forward, deletion changeset
1141: FeatureDiffReader fdr = fs.getDifferences("4", "5",
1142: Filter.INCLUDE, null);
1143: assertEquals(fs.getSchema(), fdr.getSchema());
1144: assertTrue(fdr.hasNext());
1145: FeatureDiff diff = fdr.next();
1146: assertEquals("river.rv2", diff.getID());
1147: assertEquals(FeatureDiff.DELETED, diff.getState());
1148: assertFalse(fdr.hasNext());
1149: fdr.close();
1150:
1151: // same changeset, but backwards
1152: fdr = fs.getDifferences("5", "4", Filter.INCLUDE, null);
1153: assertEquals(fs.getSchema(), fdr.getSchema());
1154: assertTrue(fdr.hasNext());
1155: diff = fdr.next();
1156: assertEquals("river.rv2", diff.getID());
1157: assertEquals(FeatureDiff.INSERTED, diff.getState());
1158: assertEquals("rv2 v3", diff.getFeature().getAttribute("river"));
1159: assertEquals(new Double(3.0), diff.getFeature().getAttribute(
1160: "flow"));
1161: // ... can't compare directly, they have different geometry factories
1162: // (afaik)
1163: assertTrue(DataUtilities.attributesEqual(lines(new int[][] { {
1164: 200, 200, 120, 120 } }), diff.getFeature()
1165: .getDefaultGeometry()));
1166: assertFalse(fdr.hasNext());
1167: fdr.close();
1168:
1169: // forward diff, two modifications on changeset 1-2, and check reader reset while
1170: // you're at it
1171: fdr = fs.getDifferences("1", "2", Filter.INCLUDE, null);
1172: for (int i = 0; i < 2; i++) {
1173: fdr.reset();
1174: assertEquals(fs.getSchema(), fdr.getSchema());
1175: Set ids = new HashSet(Arrays.asList(new String[] {
1176: "river.rv1", "river.rv2" }));
1177: assertTrue(fdr.hasNext());
1178: while (fdr.hasNext()) {
1179: diff = fdr.next();
1180: assertTrue("Unexpected id: " + diff.getID(), ids
1181: .remove(diff.getID()));
1182: assertEquals("1", fdr.getFromVersion());
1183: assertEquals("2", fdr.getToVersion());
1184: assertEquals(FeatureDiff.UPDATED, diff.state);
1185: if (diff.getID().equals("river.rv1")) {
1186: assertEquals(2, diff.getChangedAttributes().size());
1187: assertTrue(diff.getChangedAttributes().contains(
1188: "river"));
1189: assertTrue(diff.getChangedAttributes().contains(
1190: "flow"));
1191: assertEquals("rv1 v2", diff.getFeature()
1192: .getAttribute("river"));
1193: assertEquals(new Double(9.6), diff.getFeature()
1194: .getAttribute("flow"));
1195: } else {
1196: assertEquals(2, diff.getChangedAttributes().size());
1197: assertEquals("rv2 v2", diff.getFeature()
1198: .getAttribute("river"));
1199: assertTrue(DataUtilities
1200: .attributesEqual(lines(new int[][] { { 100,
1201: 100, 120, 120 } }), diff
1202: .getFeature().getAttribute("geom")));
1203: }
1204: }
1205: }
1206: fdr.close();
1207:
1208: // forward diff on creation
1209: fdr = fs.getDifferences("3", "4", Filter.INCLUDE, null);
1210: assertEquals(fs.getSchema(), fdr.getSchema());
1211: assertTrue(fdr.hasNext());
1212: diff = fdr.next();
1213: assertEquals(FeatureDiff.INSERTED, diff.getState());
1214: assertEquals(fs.getSchema(), diff.getFeature().getFeatureType());
1215: assertFalse(fdr.hasNext());
1216: fdr.close();
1217: }
1218:
1219: /**
1220: * Create history, rollback it, diff used to report changes anyways
1221: * @throws IOException
1222: * @throws IllegalAttributeException
1223: */
1224: public void testRollbackDiff() throws IOException,
1225: IllegalAttributeException {
1226: VersionedPostgisDataStore ds = getDataStore();
1227: buildRiverHistory();
1228:
1229: // try to rollback to revision 1, that is, rollback everything
1230: Transaction t = createTransaction("Mambo",
1231: "Restarting the world");
1232: VersionedPostgisFeatureStore fs = (VersionedPostgisFeatureStore) ds
1233: .getFeatureSource("river");
1234: fs.setTransaction(t);
1235: fs.rollback("1", Filter.INCLUDE, null);
1236: t.commit();
1237:
1238: // now extract a diff between current revision and the last one
1239: FeatureDiffReader reader = fs.getDifferences("1", null, null,
1240: null);
1241: assertFalse(reader.hasNext());
1242: reader.close();
1243: t.close();
1244: }
1245:
1246: public void testVersionedCollection() throws Exception {
1247: VersionedPostgisDataStore ds = getDataStore();
1248: buildRiverHistory();
1249:
1250: VersioningFeatureSource fs = (VersioningFeatureSource) ds
1251: .getFeatureSource("river");
1252: // smoke test, can we get it?
1253: FeatureCollection vfc = fs.getVersionedFeatures();
1254: FeatureCollection fc = fs.getFeatures();
1255: assertEquals(vfc.size(), fc.size());
1256: final int vfcAttributesCount = vfc.getSchema()
1257: .getAttributeCount();
1258: assertEquals(fc.getSchema().getAttributeCount() + 8,
1259: vfcAttributesCount);
1260: assertEquals("creationVersion", vfc.getSchema()
1261: .getAttributeType(0).getLocalName());
1262: assertEquals("createdBy", vfc.getSchema().getAttributeType(1)
1263: .getLocalName());
1264: assertEquals("creationDate", vfc.getSchema()
1265: .getAttributeType(2).getLocalName());
1266: assertEquals("creationMessage", vfc.getSchema()
1267: .getAttributeType(3).getLocalName());
1268: assertEquals("lastUpdateVersion", vfc.getSchema()
1269: .getAttributeType(4).getLocalName());
1270: assertEquals("lastUpdatedBy", vfc.getSchema().getAttributeType(
1271: 5).getLocalName());
1272: assertEquals("lastUpdateDate", vfc.getSchema()
1273: .getAttributeType(6).getLocalName());
1274: assertEquals("lastUpdateMessage", vfc.getSchema()
1275: .getAttributeType(7).getLocalName());
1276: final FeatureIterator vfr = vfc.features();
1277: final FeatureIterator fr = fc.features();
1278: final Feature vf = vfr.next();
1279: final Feature f = fr.next();
1280: vfr.close();
1281: fr.close();
1282: assertEquals(fc.getSchema().getTypeName(), vfc.getSchema()
1283: .getTypeName());
1284: assertEquals(f.getFeatureType().getTypeName(), vf
1285: .getFeatureType().getTypeName());
1286: assertEquals(vfcAttributesCount, vfc.getSchema()
1287: .getAttributeCount());
1288: assertEquals(f.getID(), vf.getID());
1289: for (int i = 0; i < f.getFeatureType().getAttributeCount(); i++) {
1290: assertTrue(DataUtilities.attributesEqual(f.getAttribute(i),
1291: vf.getAttribute(i + 8)));
1292: }
1293: }
1294:
1295: public void testReprojectedVersionedCollection() throws Exception {
1296: VersionedPostgisDataStore ds = getDataStore();
1297: ds
1298: .setVersioned("rail", true, "mambo",
1299: "version enabling stuff");
1300:
1301: VersioningFeatureSource fs = (VersioningFeatureSource) ds
1302: .getFeatureSource("rail");
1303: DefaultQuery dq = new DefaultQuery();
1304: final CoordinateReferenceSystem epsg3003 = CRS
1305: .decode("EPSG:3003");
1306: dq.setCoordinateSystemReproject(epsg3003);
1307: FeatureCollection fc = fs.getVersionedFeatures(dq);
1308: assertEquals(epsg3003, fc.getSchema().getDefaultGeometry()
1309: .getCoordinateSystem());
1310: }
1311:
1312: public void testMissingVersionedCollection() throws Exception {
1313: VersionedPostgisDataStore ds = getDataStore();
1314: buildRiverHistory();
1315:
1316: // drop the versioning collection view to make the db in the
1317: // same condition as an old db
1318: Connection conn = null;
1319: Statement st = null;
1320: try {
1321: conn = pool.getConnection();
1322: st = conn.createStatement();
1323: st.execute("drop view river_vfc_view");
1324: } catch (Exception e) {
1325:
1326: }
1327:
1328: VersioningFeatureSource fs = (VersioningFeatureSource) ds
1329: .getFeatureSource("river");
1330: // now, will the datastore create the view on the fly?
1331: FeatureCollection vfc = fs.getVersionedFeatures();
1332: FeatureCollection fc = fs.getFeatures();
1333: assertEquals(vfc.size(), fc.size());
1334: assertEquals(vfc.getSchema().getDefaultGeometry(), fc
1335: .getSchema().getDefaultGeometry());
1336: }
1337:
1338: public void testVersionedCollectionFidFilter() throws Exception {
1339: VersionedPostgisDataStore ds = getDataStore();
1340: buildRiverHistory();
1341:
1342: // drop the versioning collection view to make the db in the
1343: // same condition as an old db
1344: Connection conn = null;
1345: Statement st = null;
1346: try {
1347: conn = pool.getConnection();
1348: st = conn.createStatement();
1349: st.execute("drop view river_vfc_view");
1350: } catch (Exception e) {
1351:
1352: }
1353:
1354: VersioningFeatureSource fs = (VersioningFeatureSource) ds
1355: .getFeatureSource("river");
1356: final Id fidFilter = ff.id(Collections.singleton(ff
1357: .featureId("river.rv1")));
1358: FeatureCollection vfc = fs.getVersionedFeatures(fidFilter);
1359: FeatureCollection fc = fs.getFeatures(fidFilter);
1360: assertEquals(vfc.size(), fc.size());
1361: assertEquals(1, vfc.size());
1362: }
1363:
1364: /**
1365: * Version enables rivers
1366: *
1367: * @param ds
1368: * @return
1369: * @throws IOException
1370: * @throws IllegalAttributeException
1371: */
1372: protected String buildRiverHistory() throws IOException,
1373: IllegalAttributeException {
1374: VersionedPostgisDataStore ds = getDataStore();
1375: ds.setVersioned("river", true, "mambo",
1376: "version enabling stuff");
1377:
1378: // revision 2), modify two elements, rv1 and rv2
1379: Transaction t = createTransaction("lamb", "first change");
1380: FeatureWriter fw = ds.getFeatureWriter("river", Filter.INCLUDE,
1381: t);
1382: while (fw.hasNext()) {
1383: Feature f = fw.next();
1384: if (f.getID().equals("river.rv1")) {
1385: f.setAttribute("river", "rv1 v2");
1386: f.setAttribute("flow", new Double(9.6));
1387: } else {
1388: f.setAttribute("river", "rv2 v2");
1389: f.setAttribute("geom", lines(new int[][] { { 100, 100,
1390: 120, 120 } }));
1391: }
1392: fw.write();
1393: }
1394: fw.close();
1395: t.commit();
1396: t.close();
1397:
1398: // revision 3) modify just one, rv2
1399: t = createTransaction("trout", "second change");
1400: fw = ds.getFeatureWriter("river", Filter.INCLUDE, t);
1401: while (fw.hasNext()) {
1402: Feature f = fw.next();
1403: if (f.getID().equals("river.rv2")) {
1404: f.setAttribute("river", "rv2 v3");
1405: f.setAttribute("geom", lines(new int[][] { { 200, 200,
1406: 120, 120 } }));
1407: }
1408: fw.write();
1409: }
1410: fw.close();
1411: t.commit();
1412: t.close();
1413:
1414: // revision 4) create a new feature, rv3
1415: t = createTransaction("lamb", "third change");
1416: fw = ds.getFeatureWriterAppend("river", t);
1417: Feature f = fw.next();
1418: f.setAttribute("id", new Integer(3));
1419: f.setAttribute("geom",
1420: lines(new int[][] { { 300, 300, 301, 301 } }));
1421: f.setAttribute("river", "rv2 v3");
1422: f.setAttribute("flow", new Double(12.2));
1423: fw.write();
1424: String newId = f.getID();
1425: fw.close();
1426: t.commit();
1427: t.close();
1428:
1429: // revision 5), delete river rv2
1430: t = createTransaction("trout", "fourth change");
1431: fw = ds.getFeatureWriter("river", Filter.INCLUDE, t);
1432: while (fw.hasNext()) {
1433: f = fw.next();
1434: if (f.getID().equals("river.rv2")) {
1435: fw.remove();
1436: } else {
1437: fw.write();
1438: }
1439: }
1440: fw.close();
1441: t.commit();
1442: t.close();
1443: return newId;
1444: }
1445:
1446: private Transaction createTransaction(String author, String message)
1447: throws IOException {
1448: Transaction t = new DefaultTransaction();
1449: t.putProperty(VersionedPostgisDataStore.AUTHOR, author);
1450: t.putProperty(VersionedPostgisDataStore.MESSAGE, message);
1451: return t;
1452: }
1453:
1454: public static void main(String[] args) {
1455: junit.textui.TestRunner runner = new junit.textui.TestRunner();
1456: runner.setPrinter(new ResultPrinter(System.out) {
1457:
1458: public void startTest(Test test) {
1459: getWriter().println("About to run " + test);
1460: super .startTest(test);
1461: }
1462:
1463: public void endTest(Test test) {
1464: super .endTest(test);
1465: System.gc();
1466: System.gc();
1467: System.gc();
1468: Runtime.getRuntime().runFinalization();
1469: getWriter().println("Test ended: " + test);
1470: getWriter().println();
1471: }
1472:
1473: });
1474: runner
1475: .doRun(new TestSuite(
1476: VersionedOperationsOnlineTest.class));
1477: }
1478: }
|