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.SQLException;
0021: import java.sql.Statement;
0022: import java.util.NoSuchElementException;
0023: import java.util.logging.Logger;
0024:
0025: import org.geotools.data.DataUtilities;
0026: import org.geotools.data.DefaultQuery;
0027: import org.geotools.data.DefaultTransaction;
0028: import org.geotools.data.FeatureLock;
0029: import org.geotools.data.FeatureLockException;
0030: import org.geotools.data.FeatureLockFactory;
0031: import org.geotools.data.FeatureLocking;
0032: import org.geotools.data.FeatureReader;
0033: import org.geotools.data.FeatureSource;
0034: import org.geotools.data.FeatureStore;
0035: import org.geotools.data.FeatureWriter;
0036: import org.geotools.data.FilteringFeatureReader;
0037: import org.geotools.data.InProcessLockingManager;
0038: import org.geotools.data.Query;
0039: import org.geotools.data.Transaction;
0040: import org.geotools.data.jdbc.fidmapper.FIDMapper;
0041: import org.geotools.data.jdbc.fidmapper.TypedFIDMapper;
0042: import org.geotools.data.postgis.fidmapper.OIDFidMapper;
0043: import org.geotools.factory.Hints;
0044: import org.geotools.feature.AttributeType;
0045: import org.geotools.feature.AttributeTypeFactory;
0046: import org.geotools.feature.Feature;
0047: import org.geotools.feature.FeatureCollection;
0048: import org.geotools.feature.FeatureIterator;
0049: import org.geotools.feature.FeatureType;
0050: import org.geotools.feature.FeatureTypeBuilder;
0051: import org.geotools.feature.IllegalAttributeException;
0052: import org.geotools.feature.SimpleFeature;
0053: import org.geotools.filter.AbstractFilter;
0054: import org.geotools.filter.CompareFilter;
0055: import org.geotools.filter.Expression;
0056: import org.geotools.filter.Filter;
0057: import org.geotools.filter.FilterFactory;
0058: import org.geotools.filter.FilterFactoryFinder;
0059: import org.geotools.filter.FilterType;
0060: import org.geotools.filter.FunctionExpression;
0061: import org.geotools.filter.IllegalFilterException;
0062: import org.geotools.filter.function.FilterFunction_geometryType;
0063: import org.geotools.filter.function.math.FilterFunction_ceil;
0064: import org.geotools.geometry.jts.LiteCoordinateSequence;
0065: import org.geotools.geometry.jts.LiteCoordinateSequenceFactory;
0066: import org.geotools.geometry.jts.ReferencedEnvelope;
0067: import org.geotools.referencing.CRS;
0068: import org.opengis.referencing.crs.CoordinateReferenceSystem;
0069:
0070: import com.vividsolutions.jts.geom.Envelope;
0071: import com.vividsolutions.jts.geom.Geometry;
0072: import com.vividsolutions.jts.geom.GeometryFactory;
0073: import com.vividsolutions.jts.geom.LineString;
0074: import com.vividsolutions.jts.geom.Point;
0075: import com.vividsolutions.jts.geom.PrecisionModel;
0076:
0077: /**
0078: * This class tests the PostgisDataStoreAPI, against the same tests as MemoryDataStore.
0079: * <p>
0080: * The test fixture is available in the shared DataTestCase, really the common elements should move
0081: * to a shared DataStoreAPITestCase.
0082: * </p>
0083: * <p>
0084: * This class does require your own DataStore, it will create a table populated with the Features
0085: * from the test fixture, and run a test, and then remove the table.
0086: * </p>
0087: * <p>
0088: * Because of the nature of this testing process you cannot run these tests in conjunction with
0089: * another user, so they cannot be implemented against the public server.
0090: * </p>
0091: * <p>
0092: * A simple properties file has been constructed, <code>fixture.properties</code>, which you may
0093: * direct to your own potgis database installation.
0094: * </p>
0095: *
0096: * @author Jody Garnett, Refractions Research
0097: * @source $URL:
0098: * http://svn.geotools.org/geotools/trunk/gt/modules/plugin/postgis/src/test/java/org/geotools/data/postgis/PostgisDataStoreAPIOnlineTest.java $
0099: */
0100: public class PostgisDataStoreAPIOnlineTest extends
0101: AbstractPostgisDataTestCase {
0102:
0103: private static final int LOCK_DURATION = 3600 * 1000; // one hour
0104:
0105: /** The logger for the filter module. */
0106: private static final Logger LOGGER = org.geotools.util.logging.Logging
0107: .getLogger("org.geotools.data.postgis");
0108:
0109: String victim = null; // "testGetFeatureWriterRemoveAll";
0110:
0111: /**
0112: * Constructor for MemoryDataStoreTest.
0113: *
0114: * @param test
0115: * @throws AssertionError
0116: * DOCUMENT ME!
0117: */
0118: public PostgisDataStoreAPIOnlineTest(String test) {
0119: super (test);
0120:
0121: if ((victim != null) && !test.equals(victim)) {
0122: throw new AssertionError("test supressed " + test);
0123: }
0124: }
0125:
0126: protected void tearDown() throws Exception {
0127: super .tearDown();
0128: // uncomment these lines and put breakpoints in QueryData and DefaultTransaction finalizers
0129: // to spot unclosed transactions, readers and writers
0130: // Runtime.getRuntime().gc(); Runtime.getRuntime().gc();
0131: // Runtime.getRuntime().runFinalization();
0132: }
0133:
0134: /**
0135: * This is a quick hack to have our fixture reflect the FIDs in the database.
0136: * <p>
0137: * When the dataStore learns how to preserve our FeatureIds this won't be required.
0138: * </p>
0139: *
0140: * @throws Exception
0141: */
0142: protected void updateRoadFeaturesFixture() throws Exception {
0143: Connection conn = pool.getConnection();
0144: FeatureReader reader = data.getFeatureReader(new DefaultQuery(
0145: "road", Filter.INCLUDE), Transaction.AUTO_COMMIT);
0146:
0147: Envelope bounds = new Envelope();
0148:
0149: try {
0150: SimpleFeature f;
0151:
0152: while (reader.hasNext()) {
0153: f = (SimpleFeature) reader.next();
0154:
0155: int index = ((Integer) f.getAttribute("id")).intValue() - 1;
0156: roadFeatures[index] = f;
0157: bounds.expandToInclude(f.getBounds());
0158: }
0159: } finally {
0160: reader.close();
0161: conn.close();
0162: }
0163:
0164: if (!roadBounds.equals(bounds)) {
0165: System.out.println("warning! Database changed bounds()");
0166: System.out.println("was:" + roadBounds);
0167: System.out.println("now:" + bounds);
0168: roadBounds = bounds;
0169: }
0170:
0171: Envelope bounds12 = new Envelope();
0172: bounds12.expandToInclude(roadFeatures[0].getBounds());
0173: bounds12.expandToInclude(roadFeatures[1].getBounds());
0174:
0175: if (!rd12Bounds.equals(bounds12)) {
0176: System.out
0177: .println("warning! Database changed bounds of rd1 & rd2");
0178: System.out.println("was:" + rd12Bounds);
0179: System.out.println("now:" + bounds12);
0180: rd12Bounds = bounds12;
0181: }
0182:
0183: FeatureType schema = roadFeatures[0].getFeatureType();
0184: FilterFactory factory = FilterFactoryFinder
0185: .createFilterFactory();
0186: CompareFilter tFilter = factory
0187: .createCompareFilter(AbstractFilter.COMPARE_EQUALS);
0188: Expression rd1Literal = factory.createLiteralExpression("r1");
0189: tFilter.addLeftValue(rd1Literal);
0190:
0191: Expression rdNameAtt = factory.createAttributeExpression(
0192: schema, "name");
0193: tFilter.addRightValue(rdNameAtt);
0194: rd1Filter = tFilter;
0195:
0196: tFilter = factory
0197: .createCompareFilter(AbstractFilter.COMPARE_EQUALS);
0198:
0199: Expression rd2Literal = factory.createLiteralExpression("r2");
0200: tFilter.addLeftValue(rd2Literal);
0201: tFilter.addRightValue(rdNameAtt);
0202: rd2Filter = tFilter;
0203:
0204: rd12Filter = ff.or(rd2Filter, rd1Filter);
0205: }
0206:
0207: /**
0208: * This is a quick hack to have our fixture reflect the FIDs in the database.
0209: * <p>
0210: * When the dataStore learns how to preserve our FeatureIds this won't be required.
0211: * </p>
0212: *
0213: * @throws Exception
0214: * DOCUMENT ME!
0215: */
0216: protected void updateRiverFeaturesFixture() throws Exception {
0217: Connection conn = pool.getConnection();
0218: FeatureReader reader = data.getFeatureReader(new DefaultQuery(
0219: "river", Filter.INCLUDE), Transaction.AUTO_COMMIT);
0220:
0221: Envelope bounds = new Envelope();
0222:
0223: try {
0224: Feature f;
0225:
0226: while (reader.hasNext()) {
0227: f = reader.next();
0228:
0229: int index = ((Integer) f.getAttribute("id")).intValue() - 1;
0230: riverFeatures[index] = f;
0231: bounds.expandToInclude(f.getBounds());
0232: }
0233: } finally {
0234: reader.close();
0235: conn.close();
0236: }
0237:
0238: if (!riverBounds.equals(bounds)) {
0239: System.out
0240: .println("warning! Database changed bounds of river");
0241: System.out.println("was:" + riverBounds);
0242: System.out.println("now:" + bounds);
0243: riverBounds = bounds;
0244: }
0245:
0246: FilterFactory factory = FilterFactoryFinder
0247: .createFilterFactory();
0248: CompareFilter tFilter = factory
0249: .createCompareFilter(AbstractFilter.COMPARE_EQUALS);
0250: Expression rvLiteral = factory.createLiteralExpression("rv1");
0251: tFilter.addLeftValue(rvLiteral);
0252:
0253: FeatureType schema = riverFeatures[0].getFeatureType();
0254: Expression rvNameAtt = factory.createAttributeExpression(
0255: schema, "river");
0256: tFilter.addRightValue(rvNameAtt);
0257: rv1Filter = tFilter;
0258: }
0259:
0260: public void testGetFeatureTypes() {
0261: try {
0262: String[] names = data.getTypeNames();
0263: assertTrue(contains(names, "road"));
0264: assertTrue(contains(names, "river"));
0265: } catch (IOException e) {
0266: e.printStackTrace();
0267: fail("An IOException has been thrown!");
0268: }
0269: }
0270:
0271: boolean contains(Object[] array, Object expected) {
0272: if ((array == null) || (array.length == 0)) {
0273: return false;
0274: }
0275:
0276: for (int i = 0; i < array.length; i++) {
0277: if (array[i].equals(expected)) {
0278: return true;
0279: }
0280: }
0281:
0282: return false;
0283: }
0284:
0285: void assertContains(Object[] array, Object expected) {
0286: assertFalse(array == null);
0287: assertFalse(array.length == 0);
0288: assertNotNull(expected);
0289:
0290: for (int i = 0; i < array.length; i++) {
0291: if (array[i].equals(expected)) {
0292: return;
0293: }
0294: }
0295:
0296: fail("Contains " + expected);
0297: }
0298:
0299: /**
0300: * Like contain but based on match rather than equals
0301: *
0302: * @param array
0303: * DOCUMENT ME!
0304: * @param expected
0305: * DOCUMENT ME!
0306: * @return DOCUMENT ME!
0307: */
0308: boolean containsLax(Feature[] array, Feature expected) {
0309: if ((array == null) || (array.length == 0)) {
0310: return false;
0311: }
0312:
0313: FeatureType type = expected.getFeatureType();
0314:
0315: for (int i = 0; i < array.length; i++) {
0316: if (match(array[i], expected)) {
0317: return true;
0318: }
0319: }
0320:
0321: return false;
0322: }
0323:
0324: /**
0325: * Compare based on attributes not getID allows comparison of Diff contents
0326: *
0327: * @param expected
0328: * DOCUMENT ME!
0329: * @param actual
0330: * DOCUMENT ME!
0331: * @return DOCUMENT ME!
0332: */
0333: boolean match(Feature expected, Feature actual) {
0334: FeatureType type = expected.getFeatureType();
0335:
0336: for (int i = 0; i < type.getAttributeCount(); i++) {
0337: Object av = actual.getAttribute(i);
0338: Object ev = expected.getAttribute(i);
0339:
0340: if ((av == null) && (ev != null)) {
0341: return false;
0342: } else if ((ev == null) && (av != null)) {
0343: return false;
0344: } else if (av instanceof Geometry && ev instanceof Geometry) {
0345: Geometry ag = (Geometry) av;
0346: Geometry eg = (Geometry) ev;
0347:
0348: if (!ag.equals(eg)) {
0349: return false;
0350: }
0351: } else if (!av.equals(ev)) {
0352: return false;
0353: }
0354: }
0355:
0356: return true;
0357: }
0358:
0359: public void testGetSchemaRoad() throws IOException {
0360: FeatureType expected = roadType;
0361: FeatureType actual = data.getSchema("road");
0362: assertEquals("namespace", expected.getNamespace(), actual
0363: .getNamespace());
0364: assertEquals("typeName", expected.getTypeName(), actual
0365: .getTypeName());
0366:
0367: // assertEquals( "compare", 0, DataUtilities.compare( expected, actual ));
0368: assertEquals("attributeCount", expected.getAttributeCount(),
0369: actual.getAttributeCount());
0370:
0371: for (int i = 0; i < expected.getAttributeCount(); i++) {
0372: AttributeType expectedAttribute = expected
0373: .getAttributeType(i);
0374: AttributeType actualAttribute = actual.getAttributeType(i);
0375: assertEquals("attribute " + expectedAttribute.getName(),
0376: expectedAttribute, actualAttribute);
0377: }
0378:
0379: // make sure the geometry is nillable and has minOccurrs to 0
0380: AttributeType dg = actual.getDefaultGeometry();
0381: assertTrue(dg.isNillable());
0382: assertEquals(0, dg.getMinOccurs());
0383:
0384: assertEquals(expected, actual);
0385: }
0386:
0387: public void testGetSchemaRoadUnregisteredGeomColumn()
0388: throws Exception {
0389: Connection conn = pool.getConnection();
0390: conn.setAutoCommit(true);
0391: Statement st = conn.createStatement();
0392: int deleted = st
0393: .executeUpdate("DELETE FROM geometry_columns WHERE f_table_name = 'road' and f_table_schema = '"
0394: + f.schema + "'");
0395: assertEquals(1, deleted);
0396:
0397: testGetSchemaRoad();
0398: }
0399:
0400: public void testGetSchemaRiver() throws IOException {
0401: FeatureType expected = riverType;
0402: FeatureType actual = data.getSchema("river");
0403: assertEquals("namespace", expected.getNamespace(), actual
0404: .getNamespace());
0405: assertEquals("typeName", expected.getTypeName(), actual
0406: .getTypeName());
0407:
0408: // assertEquals( "compare", 0, DataUtilities.compare( expected, actual ));
0409: assertEquals("attributeCount", expected.getAttributeCount(),
0410: actual.getAttributeCount());
0411:
0412: for (int i = 0; i < expected.getAttributeCount(); i++) {
0413: AttributeType expectedAttribute = expected
0414: .getAttributeType(i);
0415: AttributeType actualAttribute = actual.getAttributeType(i);
0416: assertEquals("attribute " + expectedAttribute.getName(),
0417: expectedAttribute, actualAttribute);
0418: }
0419:
0420: // make sure the geometry is nillable and has minOccurrs to 0
0421: AttributeType dg = actual.getDefaultGeometry();
0422: assertTrue(dg.isNillable());
0423: assertEquals(0, dg.getMinOccurs());
0424:
0425: assertEquals(expected, actual);
0426: }
0427:
0428: public void testCreateSchema() throws Exception {
0429: String featureTypeName = "stuff";
0430:
0431: // delete the table, if it exists
0432: try {
0433: Connection conn = pool.getConnection();
0434: conn.setAutoCommit(true);
0435: Statement st = conn.createStatement();
0436: String sql = "DROP TABLE " + featureTypeName + ";";
0437: st.execute(sql);
0438: conn.close();
0439: } catch (Exception e) {
0440: // table didn't exist
0441: }
0442:
0443: // create a featureType and write it to PostGIS
0444: CoordinateReferenceSystem crs = CRS.decode("EPSG:4326"); // requires gt2-epsg-wkt
0445: AttributeType at1 = AttributeTypeFactory.newAttributeType("id",
0446: Integer.class);
0447: AttributeType at2 = AttributeTypeFactory.newAttributeType(
0448: "name", String.class, false, 256);
0449: AttributeType at3 = AttributeTypeFactory.newAttributeType(
0450: "the_geom", Point.class, false, Filter.INCLUDE, null,
0451: crs);
0452: AttributeType[] atts = new AttributeType[] { at1, at2, at3 };
0453:
0454: FeatureType newFT = FeatureTypeBuilder.newFeatureType(atts,
0455: featureTypeName);
0456: data.createSchema(newFT);
0457: FeatureType newSchema = data.getSchema(featureTypeName);
0458: assertNotNull(newSchema);
0459: assertEquals(3, newSchema.getAttributeCount());
0460: }
0461:
0462: static public void assertEquals(String message, String expected,
0463: String actual) {
0464: if (expected == actual) {
0465: return;
0466: }
0467:
0468: assertNotNull(message, expected);
0469: assertNotNull(message, actual);
0470:
0471: if (!expected.equals(actual)) {
0472: fail(message + " expected:<" + expected + "> but was <"
0473: + actual + ">");
0474: }
0475: }
0476:
0477: void assertCovers(String msg, FeatureCollection c1,
0478: FeatureCollection c2) {
0479: if (c1 == c2) {
0480: return;
0481: }
0482:
0483: assertNotNull(msg, c1);
0484: assertNotNull(msg, c2);
0485: assertEquals(msg + " size", c1.size(), c2.size());
0486:
0487: Feature f;
0488:
0489: for (FeatureIterator i = c1.features(); i.hasNext();) {
0490: f = i.next();
0491: assertTrue(msg + " " + f.getID(), c2.contains(f));
0492: }
0493: }
0494:
0495: public FeatureReader reader(String typeName) throws IOException {
0496: return data.getFeatureReader(new DefaultQuery(typeName,
0497: Filter.INCLUDE), Transaction.AUTO_COMMIT);
0498: }
0499:
0500: public FeatureWriter writer(String typeName) throws IOException {
0501: return data.getFeatureWriter(typeName, Transaction.AUTO_COMMIT);
0502: }
0503:
0504: public void testGetFeatureReader() throws IOException,
0505: IllegalAttributeException {
0506: assertCovered(roadFeatures, reader("road"));
0507: assertEquals(3, count(reader("road")));
0508: }
0509:
0510: public void testGeometryFactoryHintsGF() throws IOException {
0511: FeatureSource fs = data.getFeatureSource("road");
0512: assertTrue(fs.getSupportedHints().contains(
0513: Hints.JTS_GEOMETRY_FACTORY));
0514:
0515: DefaultQuery q = new DefaultQuery("road");
0516: GeometryFactory gf = new GeometryFactory(
0517: new LiteCoordinateSequenceFactory());
0518: Hints hints = new Hints(Hints.JTS_GEOMETRY_FACTORY, gf);
0519: q.setHints(hints);
0520: FeatureIterator it = fs.getFeatures(q).features();
0521: Feature f = it.next();
0522: it.close();
0523:
0524: LineString ls = (LineString) f.getDefaultGeometry();
0525: assertTrue(ls.getCoordinateSequence() instanceof LiteCoordinateSequence);
0526: }
0527:
0528: public void testGeometryFactoryHintsCS() throws IOException {
0529: FeatureSource fs = data.getFeatureSource("road");
0530: assertTrue(fs.getSupportedHints().contains(
0531: Hints.JTS_COORDINATE_SEQUENCE_FACTORY));
0532:
0533: DefaultQuery q = new DefaultQuery("road");
0534: Hints hints = new Hints(Hints.JTS_COORDINATE_SEQUENCE_FACTORY,
0535: new LiteCoordinateSequenceFactory());
0536: q.setHints(hints);
0537: FeatureIterator it = fs.getFeatures(q).features();
0538: Feature f = it.next();
0539: it.close();
0540:
0541: LineString ls = (LineString) f.getDefaultGeometry();
0542: assertTrue(ls.getCoordinateSequence() instanceof LiteCoordinateSequence);
0543: }
0544:
0545: public void testGetFeatureReaderFilterPrePost() throws IOException,
0546: IllegalFilterException {
0547: Transaction t = new DefaultTransaction();
0548: FeatureReader reader;
0549:
0550: FilterFactory factory = FilterFactoryFinder
0551: .createFilterFactory();
0552: FilterFunction_geometryType geomTypeExpr = new FilterFunction_geometryType();
0553: geomTypeExpr.setArgs(new Expression[] { factory
0554: .createAttributeExpression("geom") });
0555:
0556: CompareFilter filter = factory
0557: .createCompareFilter(FilterType.COMPARE_EQUALS);
0558: filter.addLeftValue(geomTypeExpr);
0559: filter
0560: .addRightValue(factory
0561: .createLiteralExpression("Polygon"));
0562:
0563: reader = data.getFeatureReader(
0564: new DefaultQuery("road", filter), t);
0565: // if the above statement didn't throw an exception, we're content
0566: assertNotNull(reader);
0567: reader.close();
0568: t.close();
0569: }
0570:
0571: public void testGetFeatureReaderFilterPrePost2()
0572: throws IOException, IllegalFilterException {
0573: // GEOT-1069, make sure the post filter is run even if the geom property is not requested
0574: Transaction t = new DefaultTransaction();
0575: FeatureReader reader;
0576:
0577: FilterFactory factory = FilterFactoryFinder
0578: .createFilterFactory();
0579: FilterFunction_geometryType geomTypeExpr = new FilterFunction_geometryType();
0580: geomTypeExpr.setArgs(new Expression[] { factory
0581: .createAttributeExpression("geom") });
0582:
0583: CompareFilter filter = factory
0584: .createCompareFilter(FilterType.COMPARE_EQUALS);
0585: filter.addLeftValue(geomTypeExpr);
0586: filter
0587: .addRightValue(factory
0588: .createLiteralExpression("Polygon"));
0589:
0590: reader = data.getFeatureReader(
0591: new DefaultQuery("road", filter), t);
0592: // if the above statement didn't throw an exception, we're content
0593: assertNotNull(reader);
0594: reader.close();
0595: t.close();
0596: }
0597:
0598: public void testGetFeatureReaderRetypeBug() throws Exception {
0599: // this is here to avoid http://jira.codehaus.org/browse/GEOT-1069
0600: // to come up again
0601:
0602: Transaction t = new DefaultTransaction();
0603: FeatureType type = data.getSchema("river");
0604: FeatureReader reader;
0605:
0606: FilterFactory ff = FilterFactoryFinder.createFilterFactory();
0607: CompareFilter cf = ff
0608: .createCompareFilter(Filter.COMPARE_EQUALS);
0609: cf.addLeftValue(ff.createAttributeExpression("flow"));
0610: cf.addRightValue(ff.createLiteralExpression(4.5));
0611:
0612: DefaultQuery q = new DefaultQuery("river");
0613: q.setPropertyNames(new String[] { "geom" });
0614: q.setFilter(cf);
0615:
0616: // with GEOT-1069 an exception is thrown here
0617: reader = data.getFeatureReader(q, t);
0618: assertTrue(reader.hasNext());
0619: assertEquals(1, reader.getFeatureType().getAttributeCount());
0620: reader.next();
0621: assertFalse(reader.hasNext());
0622: reader.close();
0623: t.close();
0624: }
0625:
0626: public void testGetFeatureReaderRetypeBug2() throws Exception {
0627: // this is here to avoid http://jira.codehaus.org/browse/GEOT-1069
0628: // to come up again
0629:
0630: Transaction t = new DefaultTransaction();
0631: FeatureType type = data.getSchema("river");
0632: FeatureReader reader;
0633:
0634: FilterFactory ff = FilterFactoryFinder.createFilterFactory();
0635: CompareFilter cf = ff
0636: .createCompareFilter(Filter.COMPARE_EQUALS);
0637: FunctionExpression ceil = new FilterFunction_ceil();
0638: ceil.setArgs(new Expression[] { ff
0639: .createAttributeExpression("flow") });
0640: cf.addLeftValue(ceil);
0641: cf.addRightValue(ff.createLiteralExpression(5));
0642:
0643: DefaultQuery q = new DefaultQuery("river");
0644: q.setPropertyNames(new String[] { "geom" });
0645: q.setFilter(cf);
0646:
0647: // with GEOT-1069 an exception is thrown here
0648: reader = data.getFeatureReader(q, t);
0649: assertTrue(reader.hasNext());
0650: assertEquals(1, reader.getFeatureType().getAttributeCount());
0651: reader.next();
0652: assertFalse(reader.hasNext());
0653: reader.close();
0654: t.close();
0655: }
0656:
0657: public void testGetFeatureReaderMutability() throws IOException,
0658: IllegalAttributeException {
0659: FeatureReader reader = reader("road");
0660: Feature feature;
0661:
0662: while (reader.hasNext()) {
0663: feature = (Feature) reader.next();
0664: feature.setAttribute("name", null);
0665: }
0666:
0667: reader.close();
0668:
0669: reader = reader("road");
0670:
0671: while (reader.hasNext()) {
0672: feature = (Feature) reader.next();
0673: assertNotNull(feature.getAttribute("name"));
0674: }
0675:
0676: reader.close();
0677:
0678: try {
0679: reader.next();
0680: fail("next should fail with an IOException");
0681: } catch (IOException expected) {
0682: }
0683: }
0684:
0685: public void testGetFeatureReaderConcurrency()
0686: throws NoSuchElementException, IOException,
0687: IllegalAttributeException {
0688: FeatureReader reader1 = reader("road");
0689: FeatureReader reader2 = reader("road");
0690: FeatureReader reader3 = reader("river");
0691:
0692: Feature feature1;
0693: Feature feature2;
0694: Feature feature3;
0695:
0696: while (reader1.hasNext() || reader2.hasNext()
0697: || reader3.hasNext()) {
0698: assertTrue(contains(roadFeatures, reader1.next()));
0699: assertTrue(contains(roadFeatures, reader2.next()));
0700:
0701: if (reader3.hasNext()) {
0702: assertTrue(contains(riverFeatures, reader3.next()));
0703: }
0704: }
0705:
0706: try {
0707: reader1.next();
0708: fail("next should fail with an NoSuchElementException");
0709: } catch (NoSuchElementException expectedNoElement) {
0710: // this is new to me, I had expected an IOException
0711: }
0712:
0713: try {
0714: reader2.next();
0715: fail("next should fail with an NoSuchElementException");
0716: } catch (NoSuchElementException expectedNoElement) {
0717: }
0718:
0719: try {
0720: reader3.next();
0721: fail("next should fail with an NoSuchElementException");
0722: } catch (NoSuchElementException expectedNoElement) {
0723: }
0724:
0725: reader1.close();
0726: reader2.close();
0727: reader3.close();
0728:
0729: try {
0730: reader1.next();
0731: fail("next should fail with an IOException");
0732: } catch (IOException expectedClosed) {
0733: }
0734:
0735: try {
0736: reader2.next();
0737: fail("next should fail with an IOException");
0738: } catch (IOException expectedClosed) {
0739: }
0740:
0741: try {
0742: reader3.next();
0743: fail("next should fail with an IOException");
0744: } catch (IOException expectedClosed) {
0745: }
0746: }
0747:
0748: public void testGetFeatureReaderFilterAutoCommit()
0749: throws NoSuchElementException, IOException,
0750: IllegalAttributeException {
0751: FeatureType type = data.getSchema("road");
0752: FeatureReader reader;
0753:
0754: reader = data.getFeatureReader(new DefaultQuery("road",
0755: Filter.INCLUDE), Transaction.AUTO_COMMIT);
0756: assertFalse(reader instanceof FilteringFeatureReader);
0757: assertEquals(type, reader.getFeatureType());
0758: assertEquals(roadFeatures.length, count(reader));
0759:
0760: reader = data.getFeatureReader(new DefaultQuery("road",
0761: Filter.EXCLUDE), Transaction.AUTO_COMMIT);
0762: assertFalse(reader.hasNext());
0763:
0764: assertEquals(type, reader.getFeatureType());
0765: assertEquals(0, count(reader));
0766:
0767: reader = data.getFeatureReader(new DefaultQuery("road",
0768: rd1Filter), Transaction.AUTO_COMMIT);
0769:
0770: // assertTrue(reader instanceof FilteringFeatureReader);
0771: assertEquals(type, reader.getFeatureType());
0772: assertEquals(1, count(reader));
0773: }
0774:
0775: public void testGetFeatureReaderFilterTransaction()
0776: throws NoSuchElementException, IOException,
0777: IllegalAttributeException {
0778: Transaction t = new DefaultTransaction();
0779: FeatureType type = data.getSchema("road");
0780: FeatureReader reader;
0781:
0782: reader = data.getFeatureReader(new DefaultQuery("road",
0783: Filter.EXCLUDE), t);
0784: assertFalse(reader.hasNext());
0785: assertEquals(type, reader.getFeatureType());
0786: assertEquals(0, count(reader));
0787: reader.close();
0788:
0789: reader = data.getFeatureReader(new DefaultQuery("road",
0790: Filter.INCLUDE), t);
0791: assertEquals(type, reader.getFeatureType());
0792: assertEquals(roadFeatures.length, count(reader));
0793: reader.close();
0794:
0795: reader = data.getFeatureReader(new DefaultQuery("road",
0796: rd1Filter), t);
0797: assertEquals(type, reader.getFeatureType());
0798: assertEquals(1, count(reader));
0799: reader.close();
0800:
0801: FeatureWriter writer = data.getFeatureWriter("road",
0802: Filter.INCLUDE, t);
0803: Feature feature;
0804:
0805: while (writer.hasNext()) {
0806: feature = writer.next();
0807:
0808: if (feature.getID().equals(roadFeatures[0].getID())) {
0809: writer.remove();
0810: }
0811: }
0812: writer.close();
0813:
0814: reader = data.getFeatureReader(new DefaultQuery("road",
0815: Filter.EXCLUDE), t);
0816: assertEquals(0, count(reader));
0817: reader.close();
0818:
0819: reader = data.getFeatureReader(new DefaultQuery("road",
0820: Filter.INCLUDE), t);
0821: assertEquals(roadFeatures.length - 1, count(reader));
0822: reader.close();
0823:
0824: reader = data.getFeatureReader(new DefaultQuery("road",
0825: rd1Filter), t);
0826: assertEquals(0, count(reader));
0827: reader.close();
0828:
0829: t.rollback();
0830: reader = data.getFeatureReader(new DefaultQuery("road",
0831: Filter.EXCLUDE), t);
0832: assertEquals(0, count(reader));
0833: reader.close();
0834:
0835: reader = data.getFeatureReader(new DefaultQuery("road",
0836: Filter.INCLUDE), t);
0837: assertEquals(roadFeatures.length, count(reader));
0838: reader.close();
0839:
0840: reader = data.getFeatureReader(new DefaultQuery("road",
0841: rd1Filter), t);
0842: assertEquals(1, count(reader));
0843: reader.close();
0844: t.close();
0845: }
0846:
0847: /**
0848: * Ensure readers contents equal those in the feature array
0849: *
0850: * @param features
0851: * DOCUMENT ME!
0852: * @param reader
0853: * DOCUMENT ME!
0854: * @throws NoSuchElementException
0855: * DOCUMENT ME!
0856: * @throws IOException
0857: * DOCUMENT ME!
0858: * @throws IllegalAttributeException
0859: * DOCUMENT ME!
0860: */
0861: void assertCovered(Feature[] features, FeatureReader reader)
0862: throws NoSuchElementException, IOException,
0863: IllegalAttributeException {
0864: int count = 0;
0865:
0866: try {
0867: while (reader.hasNext()) {
0868: assertContains(features, reader.next());
0869: count++;
0870: }
0871: } finally {
0872: reader.close();
0873: }
0874:
0875: assertEquals(features.length, count);
0876: }
0877:
0878: /**
0879: * Ensure readers contents match those in the feature array
0880: * <p>
0881: * Implemented using match on attribute types, not feature id
0882: * </p>
0883: *
0884: * @param array
0885: * DOCUMENT ME!
0886: * @param reader
0887: * DOCUMENT ME!
0888: * @throws Exception
0889: * DOCUMENT ME!
0890: */
0891: void assertMatched(Feature[] array, FeatureReader reader)
0892: throws Exception {
0893: Feature feature;
0894: int count = 0;
0895:
0896: try {
0897: while (reader.hasNext()) {
0898: feature = reader.next();
0899: assertMatch(array, feature);
0900: count++;
0901: }
0902: } finally {
0903: reader.close();
0904: }
0905:
0906: assertEquals("array not matched by reader", array.length, count);
0907: }
0908:
0909: void assertMatch(Feature[] array, Feature feature) {
0910: assertTrue(array != null);
0911: assertTrue(array.length != 0);
0912:
0913: FeatureType schema = feature.getFeatureType();
0914:
0915: for (int i = 0; i < array.length; i++) {
0916: if (match(array[i], feature)) {
0917: return;
0918: }
0919: }
0920:
0921: System.out.println("not found:" + feature);
0922:
0923: for (int i = 0; i < array.length; i++) {
0924: System.out.println(i + ":" + array[i]);
0925: }
0926:
0927: fail("array has no match for " + feature);
0928: }
0929:
0930: /**
0931: * Ensure that FeatureReader reader contains exactly the contents of array.
0932: *
0933: * @param reader
0934: * DOCUMENT ME!
0935: * @param array
0936: * DOCUMENT ME!
0937: * @return DOCUMENT ME!
0938: * @throws NoSuchElementException
0939: * DOCUMENT ME!
0940: * @throws IOException
0941: * DOCUMENT ME!
0942: * @throws IllegalAttributeException
0943: * DOCUMENT ME!
0944: */
0945: boolean covers(FeatureReader reader, Feature[] array)
0946: throws NoSuchElementException, IOException,
0947: IllegalAttributeException {
0948: Feature feature;
0949: int count = 0;
0950:
0951: try {
0952: while (reader.hasNext()) {
0953: feature = reader.next();
0954:
0955: if (!contains(array, feature)) {
0956: return false;
0957: }
0958:
0959: count++;
0960: }
0961: } finally {
0962: reader.close();
0963: }
0964:
0965: return count == array.length;
0966: }
0967:
0968: boolean covers(FeatureIterator reader, Feature[] array)
0969: throws NoSuchElementException, IOException,
0970: IllegalAttributeException {
0971: Feature feature;
0972: int count = 0;
0973:
0974: try {
0975: while (reader.hasNext()) {
0976: feature = reader.next();
0977:
0978: if (!contains(array, feature)) {
0979: return false;
0980: }
0981:
0982: count++;
0983: }
0984: } finally {
0985: reader.close();
0986: }
0987:
0988: return count == array.length;
0989: }
0990:
0991: boolean coversLax(FeatureReader reader, Feature[] array)
0992: throws NoSuchElementException, IOException,
0993: IllegalAttributeException {
0994: Feature feature;
0995: int count = 0;
0996:
0997: try {
0998: while (reader.hasNext()) {
0999: feature = reader.next();
1000:
1001: if (!containsLax(array, feature)) {
1002: return false;
1003: }
1004:
1005: count++;
1006: }
1007: } finally {
1008: reader.close();
1009: }
1010:
1011: return count == array.length;
1012: }
1013:
1014: void dump(String message, FeatureReader reader)
1015: throws NoSuchElementException, IOException,
1016: IllegalAttributeException {
1017: Feature feature;
1018: int count = 0;
1019:
1020: try {
1021: while (reader.hasNext()) {
1022: feature = reader.next();
1023:
1024: String msg = message + ": feture " + count + "="
1025: + feature;
1026:
1027: // LOGGER.info( msg );
1028: System.out.println(msg);
1029: count++;
1030: }
1031: } finally {
1032: reader.close();
1033: }
1034: }
1035:
1036: void dump(String message, Object[] array) {
1037: for (int i = 0; i < array.length; i++) {
1038: String msg = message + ": " + i + "=" + array[i];
1039:
1040: // LOGGER.info( msg );
1041: System.out.println(msg);
1042: }
1043: }
1044:
1045: /*
1046: * Test for FeatureWriter getFeatureWriter(String, Filter, Transaction)
1047: */
1048: public void xtestGetFeatureWriter() throws Exception {
1049: FeatureWriter writer = data.getFeatureWriter("road",
1050: Filter.INCLUDE, Transaction.AUTO_COMMIT);
1051: assertEquals(roadFeatures.length, count(writer));
1052: }
1053:
1054: public void testGetFeatureWriterClose() throws Exception {
1055: FeatureWriter writer = data.getFeatureWriter("road",
1056: Filter.INCLUDE, Transaction.AUTO_COMMIT);
1057:
1058: writer.close();
1059:
1060: try {
1061: assertFalse(writer.hasNext());
1062: fail("Should not be able to use a closed writer");
1063: } catch (IOException expected) {
1064: }
1065:
1066: try {
1067: assertNull(writer.next());
1068: fail("Should not be able to use a closed writer");
1069: } catch (IOException expected) {
1070: }
1071:
1072: try {
1073: writer.close();
1074: } catch (IOException expected) {
1075: }
1076: }
1077:
1078: public void testGetFeatureWriterRemove() throws IOException,
1079: IllegalAttributeException {
1080: FeatureWriter writer = writer("road");
1081: Feature feature;
1082:
1083: while (writer.hasNext()) {
1084: feature = writer.next();
1085:
1086: if (feature.getID().equals(roadFeatures[0].getID())) {
1087: writer.remove();
1088: }
1089: }
1090: writer.close();
1091:
1092: assertEquals(roadFeatures.length - 1, count("road"));
1093: }
1094:
1095: public void testGetFeatureWriterRemoveAll() throws IOException,
1096: IllegalAttributeException {
1097: FeatureWriter writer = writer("road");
1098: Feature feature;
1099:
1100: try {
1101: while (writer.hasNext()) {
1102: feature = writer.next();
1103: writer.remove();
1104: }
1105: } finally {
1106: writer.close();
1107: }
1108:
1109: assertEquals(0, count("road"));
1110: }
1111:
1112: public int count(String typeName) throws IOException {
1113: // return count(reader(typeName));
1114: // makes use of optimization if any
1115: return data.getFeatureSource(typeName).getFeatures().size();
1116: }
1117:
1118: public void testGetFeaturesWriterAdd() throws IOException,
1119: IllegalAttributeException {
1120: FeatureWriter writer = data.getFeatureWriter("road",
1121: Transaction.AUTO_COMMIT);
1122: SimpleFeature feature;
1123:
1124: LOGGER.info("about to call has next on writer " + writer);
1125:
1126: while (writer.hasNext()) {
1127: feature = (SimpleFeature) writer.next();
1128: }
1129:
1130: assertFalse(writer.hasNext());
1131:
1132: feature = (SimpleFeature) writer.next();
1133: feature.setAttributes(newRoad.getAttributes(null));
1134: writer.write();
1135:
1136: assertFalse(writer.hasNext());
1137: writer.close();
1138: assertEquals(roadFeatures.length + 1, count("road"));
1139: }
1140:
1141: /**
1142: * Seach for feature based on AttributeType.
1143: * <p>
1144: * If attributeName is null, we will search by feature.getID()
1145: * </p>
1146: * <p>
1147: * The provided reader will be closed by this opperations.
1148: * </p>
1149: *
1150: * @param reader
1151: * reader to search through
1152: * @param attributeName
1153: * attributeName, or null for featureID
1154: * @param value
1155: * value to match
1156: * @return Feature
1157: * @throws NoSuchElementException
1158: * if a match could not be found
1159: * @throws IOException
1160: * We could not use reader
1161: * @throws IllegalAttributeException
1162: * if attributeName did not match schema
1163: */
1164: public Feature findFeature(FeatureReader reader,
1165: String attributeName, Object value)
1166: throws NoSuchElementException, IOException,
1167: IllegalAttributeException {
1168: Feature f;
1169:
1170: try {
1171: while (reader.hasNext()) {
1172: f = reader.next();
1173:
1174: if (attributeName == null) {
1175: if (value.equals(f.getID())) {
1176: return f;
1177: }
1178: } else {
1179: if (value.equals(f.getAttribute(attributeName))) {
1180: return f;
1181: }
1182: }
1183: }
1184: } finally {
1185: reader.close();
1186: }
1187:
1188: if (attributeName == null) {
1189: throw new NoSuchElementException("No match for FID="
1190: + value);
1191: } else {
1192: throw new NoSuchElementException("No match for "
1193: + attributeName + "=" + value);
1194: }
1195: }
1196:
1197: public Feature feature(String typeName, String fid)
1198: throws NoSuchElementException, IOException,
1199: IllegalAttributeException {
1200: FeatureReader reader = reader(typeName);
1201: Feature f;
1202:
1203: try {
1204: while (reader.hasNext()) {
1205: f = reader.next();
1206:
1207: if (fid.equals(f.getID())) {
1208: return f;
1209: }
1210: }
1211: } finally {
1212: reader.close();
1213: }
1214:
1215: return null;
1216: }
1217:
1218: public void testGetFeaturesWriterModify() throws IOException,
1219: IllegalAttributeException {
1220: FeatureWriter writer = writer("road");
1221: Feature feature;
1222:
1223: while (writer.hasNext()) {
1224: feature = writer.next();
1225:
1226: if (feature.getID().equals(roadFeatures[0].getID())) {
1227: feature.setAttribute("name", "changed");
1228: writer.write();
1229: }
1230: }
1231: writer.close();
1232:
1233: feature = (Feature) feature("road", roadFeatures[0].getID());
1234: assertNotNull(feature);
1235: assertEquals("changed", feature.getAttribute("name"));
1236: }
1237:
1238: public void testGetFeatureWriterTypeNameTransaction()
1239: throws NoSuchElementException, IOException,
1240: IllegalAttributeException {
1241: FeatureWriter writer;
1242:
1243: writer = data.getFeatureWriter("road", Transaction.AUTO_COMMIT);
1244: assertEquals(roadFeatures.length, count(writer));
1245:
1246: // writer.close(); called by count.
1247: }
1248:
1249: public void testGetFeatureWriterAppendTypeNameTransaction()
1250: throws Exception {
1251: FeatureWriter writer;
1252:
1253: writer = data.getFeatureWriterAppend("road",
1254: Transaction.AUTO_COMMIT);
1255: assertEquals(0, count(writer));
1256:
1257: // writer.close(); called by count
1258: }
1259:
1260: /*
1261: * Test for FeatureWriter getFeatureWriter(String, boolean, Transaction) @task REVISIT:
1262: * JDBCDataStore currently does not return these proper instanceof's. If we want to guarantee
1263: * that people can't append to a request with a FeatureWriter then we could add the
1264: * functionality to JDBCDataStore by having getFeatureWriter(.. Filter ...) check to see if the
1265: * FeatureWriter returned is instanceof FilteringFeatureWriter, and if not then just wrap it in
1266: * a FilteringFeatureWriter(writer, Filter.INCLUDE). I think it'd be a bit of unnecessary
1267: * overhead, but if we want it it's easy to do. It will guarantee that calls with Filter won't
1268: * ever append. Doing with Filter.INCLUDE, however, would require a bit of reworking, as the
1269: * Filter getFeatureWriter is currently where we do the bulk of the work.
1270: */
1271: public void testGetFeatureWriterFilter()
1272: throws NoSuchElementException, IOException,
1273: IllegalAttributeException {
1274: FeatureWriter writer;
1275: writer = data.getFeatureWriter("road", Filter.EXCLUDE,
1276: Transaction.AUTO_COMMIT);
1277:
1278: // see task above
1279: // assertTrue(writer instanceof EmptyFeatureWriter);
1280: assertEquals(0, count(writer));
1281:
1282: writer = data.getFeatureWriter("road", Filter.INCLUDE,
1283: Transaction.AUTO_COMMIT);
1284:
1285: // assertFalse(writer instanceof FilteringFeatureWriter);
1286: assertEquals(roadFeatures.length, count(writer));
1287:
1288: writer = data.getFeatureWriter("road", rd1Filter,
1289: Transaction.AUTO_COMMIT);
1290:
1291: // assertTrue(writer instanceof FilteringFeatureWriter);
1292: assertEquals(1, count(writer));
1293: }
1294:
1295: /**
1296: * Test two transactions one removing feature, and one adding a feature.
1297: *
1298: * @throws IllegalAttributeException
1299: * @throws Exception
1300: * DOCUMENT ME!
1301: */
1302: public void testGetFeatureWriterTransaction() throws Exception {
1303: Transaction t1 = new DefaultTransaction();
1304: Transaction t2 = new DefaultTransaction();
1305: FeatureWriter writer1 = data.getFeatureWriter("road",
1306: rd1Filter, t1);
1307: FeatureWriter writer2 = data.getFeatureWriterAppend("road", t2);
1308:
1309: FeatureType road = data.getSchema("road");
1310: FeatureReader reader;
1311: SimpleFeature feature;
1312: SimpleFeature[] ORIGINAL = roadFeatures;
1313: Feature[] REMOVE = new Feature[ORIGINAL.length - 1];
1314: Feature[] ADD = new Feature[ORIGINAL.length + 1];
1315: Feature[] FINAL = new Feature[ORIGINAL.length];
1316: int i;
1317: int index;
1318: index = 0;
1319:
1320: for (i = 0; i < ORIGINAL.length; i++) {
1321: feature = ORIGINAL[i];
1322:
1323: if (!feature.getID().equals(roadFeatures[0].getID())) {
1324: REMOVE[index++] = feature;
1325: }
1326: }
1327:
1328: for (i = 0; i < ORIGINAL.length; i++) {
1329: ADD[i] = ORIGINAL[i];
1330: }
1331:
1332: ADD[i] = newRoad; // will need to update with Fid from database
1333:
1334: for (i = 0; i < REMOVE.length; i++) {
1335: FINAL[i] = REMOVE[i];
1336: }
1337:
1338: FINAL[i] = newRoad; // will need to update with Fid from database
1339:
1340: // start off with ORIGINAL
1341: reader = data.getFeatureReader(new DefaultQuery("road",
1342: Filter.INCLUDE), Transaction.AUTO_COMMIT);
1343: assertTrue(
1344: "Sanity check failed: before modification reader didn't match original content",
1345: covers(reader, ORIGINAL));
1346: reader.close();
1347:
1348: // writer 1 removes road.rd1 on t1
1349: // -------------------------------
1350: // - tests transaction independence from DataStore
1351: while (writer1.hasNext()) {
1352: feature = (SimpleFeature) writer1.next();
1353: assertEquals(roadFeatures[0].getID(), feature.getID());
1354: writer1.remove();
1355: }
1356:
1357: // still have ORIGINAL and t1 has REMOVE
1358: reader = data.getFeatureReader(new DefaultQuery("road",
1359: Filter.INCLUDE), Transaction.AUTO_COMMIT);
1360: assertTrue(
1361: "Feature deletion managed to leak out of transaction?",
1362: covers(reader, ORIGINAL));
1363: reader.close();
1364:
1365: reader = data.getFeatureReader(new DefaultQuery("road",
1366: Filter.INCLUDE), t1);
1367: assertTrue(covers(reader, REMOVE));
1368: reader.close();
1369:
1370: // close writer1
1371: // --------------
1372: // ensure that modification is left up to transaction commmit
1373: writer1.close();
1374:
1375: // We still have ORIGIONAL and t1 has REMOVE
1376: reader = data.getFeatureReader(new DefaultQuery("road",
1377: Filter.INCLUDE), Transaction.AUTO_COMMIT);
1378: assertTrue(covers(reader, ORIGINAL));
1379: reader.close();
1380:
1381: reader = data.getFeatureReader(new DefaultQuery("road",
1382: Filter.INCLUDE), t1);
1383: assertTrue(covers(reader, REMOVE));
1384: reader.close();
1385:
1386: // writer 2 adds road.rd4 on t2
1387: // ----------------------------
1388: // - tests transaction independence from each other
1389: feature = (SimpleFeature) writer2.next();
1390: feature.setAttributes(newRoad.getAttributes(null));
1391: writer2.write();
1392:
1393: // HACK: ?!? update ADD and FINAL with new FID from database
1394: //
1395: reader = data.getFeatureReader(new DefaultQuery("road",
1396: Filter.INCLUDE), t2);
1397: newRoad = findFeature(reader, "id", new Integer(4));
1398: System.out.println("newRoad:" + newRoad);
1399: ADD[ADD.length - 1] = newRoad;
1400: FINAL[FINAL.length - 1] = newRoad;
1401: reader.close();
1402:
1403: // We still have ORIGINAL and t2 has ADD
1404: reader = data.getFeatureReader(new DefaultQuery("road",
1405: Filter.INCLUDE), Transaction.AUTO_COMMIT);
1406: assertTrue(covers(reader, ORIGINAL));
1407: reader.close();
1408:
1409: reader = data.getFeatureReader(new DefaultQuery("road",
1410: Filter.INCLUDE), t2);
1411: assertMatched(ADD, reader); // broken due to FID problem
1412: reader.close();
1413:
1414: writer2.close();
1415:
1416: // Still have ORIGIONAL and t2 has ADD
1417: reader = data.getFeatureReader(new DefaultQuery("road",
1418: Filter.INCLUDE), Transaction.AUTO_COMMIT);
1419: assertTrue(covers(reader, ORIGINAL));
1420: reader.close();
1421: reader = data.getFeatureReader(new DefaultQuery("road",
1422: Filter.INCLUDE), t2);
1423: assertTrue(coversLax(reader, ADD));
1424: reader.close();
1425:
1426: // commit t1
1427: // ---------
1428: // -ensure that delayed writing of transactions takes place
1429: //
1430: t1.commit();
1431:
1432: // We now have REMOVE, as does t1 (which has not additional diffs)
1433: // t2 will have FINAL
1434: reader = data.getFeatureReader(new DefaultQuery("road",
1435: Filter.INCLUDE), Transaction.AUTO_COMMIT);
1436: assertTrue(covers(reader, REMOVE));
1437: reader.close();
1438: reader = data.getFeatureReader(new DefaultQuery("road",
1439: Filter.INCLUDE), t1);
1440: assertTrue(covers(reader, REMOVE));
1441: reader.close();
1442: reader = data.getFeatureReader(new DefaultQuery("road",
1443: Filter.INCLUDE), t2);
1444: assertTrue(coversLax(reader, FINAL));
1445: reader.close();
1446:
1447: // commit t2
1448: // ---------
1449: // -ensure that everyone is FINAL at the end of the day
1450: t2.commit();
1451:
1452: // We now have Number( remove one and add one)
1453: reader = data.getFeatureReader(new DefaultQuery("road",
1454: Filter.INCLUDE), Transaction.AUTO_COMMIT);
1455: assertTrue(coversLax(reader, FINAL));
1456: reader.close();
1457:
1458: reader = data.getFeatureReader(new DefaultQuery("road",
1459: Filter.INCLUDE), t1);
1460: assertTrue(coversLax(reader, FINAL));
1461: reader.close();
1462:
1463: reader = data.getFeatureReader(new DefaultQuery("road",
1464: Filter.INCLUDE), t2);
1465: assertTrue(coversLax(reader, FINAL));
1466: reader.close();
1467:
1468: t1.close();
1469: t2.close();
1470: }
1471:
1472: /**
1473: * Tests that if 2 transactions attempt to modify the same feature without committing, that the
1474: * second transaction does not lock up waiting to obtain the lock.
1475: *
1476: * @author chorner
1477: * @throws IOException
1478: * @throws IllegalAttributeException
1479: * @throws SQLException
1480: */
1481: public void testGetFeatureWriterConcurrency() throws Exception {
1482: // if we don't have postgres >= 8.1, don't bother testing (it WILL block)
1483: Connection conn = null;
1484: try {
1485: conn = pool.getConnection();
1486: int major = conn.getMetaData().getDatabaseMajorVersion();
1487: int minor = conn.getMetaData().getDatabaseMinorVersion();
1488: if (!((major > 8) || ((major == 8) && minor >= 1))) {
1489: return; // concurrency support is weak
1490: }
1491: } finally {
1492: if (conn != null)
1493: conn.close();
1494: }
1495: Transaction t1 = new DefaultTransaction();
1496: FeatureWriter writer1 = data.getFeatureWriter("road",
1497: rd1Filter, t1);
1498: Feature f1 = writer1.next();
1499: f1.setAttribute("name", new String("r1_"));
1500: writer1.write();
1501:
1502: Transaction t2 = new DefaultTransaction();
1503: FeatureWriter writer2 = data.getFeatureWriter("road",
1504: rd1Filter, t2);
1505: Feature f2 = writer2.next();
1506: f2.setAttribute("name", new String("r1__"));
1507: try {
1508: writer2.write(); // this will either lock up or toss chunks
1509: fail("Feature lock should have failed");
1510: } catch (FeatureLockException e) {
1511: // success (test-wise... our write failed quite well too)
1512: assertEquals("road.rd1", e.getFeatureID());
1513: }
1514:
1515: t1.rollback(); // don't save
1516: writer1.close();
1517: t1.close();
1518:
1519: t2.rollback();
1520: writer2.close();
1521: t2.close();
1522: }
1523:
1524: // Feature Source Testing
1525: public void testGetFeatureSourceRoad() throws IOException {
1526: FeatureSource road = data.getFeatureSource("road");
1527:
1528: assertEquals(roadType, road.getSchema());
1529: assertSame(data, road.getDataStore());
1530:
1531: int count = road.getCount(Query.ALL);
1532: assertTrue((count == 3) || (count == -1));
1533:
1534: Envelope bounds = road.getBounds(Query.ALL);
1535: assertTrue((bounds == null) || bounds.equals(roadBounds));
1536:
1537: FeatureCollection all = road.getFeatures();
1538: assertEquals(3, all.size());
1539: assertEquals(roadBounds, all.getBounds());
1540:
1541: FeatureCollection expected = DataUtilities
1542: .collection(roadFeatures);
1543:
1544: assertCovers("all", expected, all);
1545: assertEquals(roadBounds, all.getBounds());
1546:
1547: FeatureCollection some = road.getFeatures(rd12Filter);
1548: assertEquals(2, some.size());
1549:
1550: Envelope e = new Envelope();
1551: e.expandToInclude(roadFeatures[0].getBounds());
1552: e.expandToInclude(roadFeatures[1].getBounds());
1553: assertEquals(e, some.getBounds());
1554: assertEquals(some.getSchema(), road.getSchema());
1555:
1556: DefaultQuery query = new DefaultQuery("road", rd12Filter,
1557: new String[] { "name" });
1558:
1559: FeatureCollection half = road.getFeatures(query);
1560: assertEquals(2, half.size());
1561: assertEquals(1, half.getSchema().getAttributeCount());
1562:
1563: FeatureIterator reader = half.features();
1564: FeatureType type = half.getSchema();
1565: reader.close();
1566:
1567: FeatureType actual = half.getSchema();
1568:
1569: assertEquals(type.getTypeName(), actual.getTypeName());
1570: assertEquals(type.getNamespace(), actual.getNamespace());
1571: assertEquals(type.getAttributeCount(), actual
1572: .getAttributeCount());
1573:
1574: for (int i = 0; i < type.getAttributeCount(); i++) {
1575: assertEquals(type.getAttributeType(i), actual
1576: .getAttributeType(i));
1577: }
1578:
1579: assertNull(type.getDefaultGeometry()); // geometry is null, therefore no bounds
1580: assertEquals(type.getDefaultGeometry(), actual
1581: .getDefaultGeometry());
1582: assertEquals(type, actual);
1583:
1584: Envelope b = half.getBounds();
1585: Envelope expectedBounds = isEnvelopeComputingEnabled() ? roadBounds
1586: : new Envelope();
1587: assertEquals(expectedBounds, b); // empty envelope is expected
1588: }
1589:
1590: public void testBoundsReproject() throws Exception {
1591: FeatureSource road = data.getFeatureSource("road");
1592: assertEquals(roadBounds, road.getBounds());
1593:
1594: CoordinateReferenceSystem epsg4326 = CRS.decode("EPSG:4326");
1595: CoordinateReferenceSystem epsg3003 = CRS.decode("EPSG:3003");
1596: ReferencedEnvelope rbOriginal = new ReferencedEnvelope(
1597: roadBounds, epsg4326);
1598: ReferencedEnvelope rbReprojected = rbOriginal.transform(
1599: epsg3003, true);
1600: DefaultQuery q = new DefaultQuery("road");
1601: q.setCoordinateSystem(epsg4326);
1602: q.setCoordinateSystemReproject(epsg3003);
1603: assertEquals(new Envelope(rbReprojected), road.getBounds(q));
1604: }
1605:
1606: /**
1607: * Return true if the datastore is capable of computing the road bounds given a query
1608: *
1609: * @return
1610: */
1611: protected boolean isEnvelopeComputingEnabled() {
1612: if (data instanceof PostgisDataStore
1613: && ((PostgisDataStore) data).isEstimatedExtent()) {
1614: return true;
1615: }
1616:
1617: return false;
1618: }
1619:
1620: public void testGetFeatureSourceRiver()
1621: throws NoSuchElementException, IOException,
1622: IllegalAttributeException {
1623: FeatureSource river = data.getFeatureSource("river");
1624:
1625: assertEquals(riverType, river.getSchema());
1626: assertSame(data, river.getDataStore());
1627:
1628: FeatureCollection all = river.getFeatures();
1629: assertEquals(2, all.size());
1630: assertEquals(riverBounds, all.getBounds());
1631: assertTrue("rivers", covers(all.features(), riverFeatures));
1632:
1633: FeatureCollection expected = DataUtilities
1634: .collection(riverFeatures);
1635: assertCovers("all", expected, all);
1636: assertEquals(riverBounds, all.getBounds());
1637: }
1638:
1639: //
1640: // Feature Store Testing
1641: //
1642: public void testGetFeatureStoreModifyFeatures1() throws IOException {
1643: FeatureStore road = (FeatureStore) data
1644: .getFeatureSource("road");
1645:
1646: // FilterFactory factory = FilterFactoryFinder.createFilterFactory();
1647: // rd1Filter = factory.createFidFilter( roadFeatures[0].getID() );
1648: Object changed = new Integer(5);
1649: AttributeType name = roadType.getAttributeType("id");
1650: road.modifyFeatures(name, changed, rd1Filter);
1651:
1652: FeatureCollection results = road.getFeatures(rd1Filter);
1653: FeatureIterator features = results.features();
1654: assertEquals(changed, features.next().getAttribute("id"));
1655: results.close(features);
1656: }
1657:
1658: public void testGetFeatureStoreModifyFeatures2() throws IOException {
1659: FeatureStore road = (FeatureStore) data
1660: .getFeatureSource("road");
1661:
1662: FilterFactory factory = FilterFactoryFinder
1663: .createFilterFactory();
1664: rd1Filter = factory.createFidFilter(roadFeatures[0].getID());
1665:
1666: AttributeType name = roadType.getAttributeType("name");
1667: road.modifyFeatures(new AttributeType[] { name, },
1668: new Object[] { "changed", }, rd1Filter);
1669:
1670: FeatureCollection results = road.getFeatures(rd1Filter);
1671: FeatureIterator features = results.features();
1672: assertEquals("changed", features.next().getAttribute("name"));
1673: results.close(features);
1674: }
1675:
1676: /**
1677: * Test with a filter that won't be matched after the modification is done, was throwing an NPE
1678: * before the fix
1679: *
1680: * @throws IOException
1681: */
1682: public void testGetFeatureStoreModifyFeatures3() throws IOException {
1683: FeatureStore road = (FeatureStore) data
1684: .getFeatureSource("road");
1685:
1686: FilterFactory factory = FilterFactoryFinder
1687: .createFilterFactory();
1688: CompareFilter filter = factory
1689: .createCompareFilter(Filter.COMPARE_EQUALS);
1690: filter.addLeftValue(ff.createAttributeExpression("name"));
1691: filter.addRightValue(ff.createLiteralExpression("r1"));
1692:
1693: AttributeType name = roadType.getAttributeType("name");
1694: road.modifyFeatures(new AttributeType[] { name, },
1695: new Object[] { "changed", }, filter);
1696: }
1697:
1698: public void testGetFeatureStoreRemoveFeatures() throws IOException {
1699: FeatureStore road = (FeatureStore) data
1700: .getFeatureSource("road");
1701:
1702: road.removeFeatures(rd1Filter);
1703: assertEquals(0, road.getFeatures(rd1Filter).size());
1704: assertEquals(roadFeatures.length - 1, road.getFeatures().size());
1705: }
1706:
1707: public void testGetFeatureStoreRemoveAllFeatures()
1708: throws IOException {
1709: FeatureStore road = (FeatureStore) data
1710: .getFeatureSource("road");
1711:
1712: road.removeFeatures(Filter.INCLUDE);
1713: assertEquals(0, road.getFeatures().size());
1714: }
1715:
1716: public void testGetFeatureStoreAddFeatures() throws IOException {
1717: FeatureReader reader = DataUtilities
1718: .reader(new Feature[] { newRoad, });
1719: FeatureStore road = (FeatureStore) data
1720: .getFeatureSource("road");
1721:
1722: road.addFeatures(DataUtilities.collection(reader));
1723: assertEquals(roadFeatures.length + 1, count("road"));
1724: }
1725:
1726: public void testGetFeatureStoreSetFeatures()
1727: throws NoSuchElementException, IOException,
1728: IllegalAttributeException {
1729: FeatureReader reader = DataUtilities
1730: .reader(new Feature[] { newRoad, });
1731:
1732: FeatureStore road = (FeatureStore) data
1733: .getFeatureSource("road");
1734:
1735: assertEquals(3, count("road"));
1736:
1737: road.setFeatures(reader);
1738:
1739: assertEquals(1, count("road"));
1740: }
1741:
1742: // public void testGetFeatureStoreTransactionSupport()
1743: // throws Exception {
1744: // Transaction t1 = new DefaultTransaction();
1745: // Transaction t2 = new DefaultTransaction();
1746: //
1747: // FeatureStore road = (FeatureStore) data.getFeatureSource("road");
1748: // FeatureStore road1 = (FeatureStore) data.getFeatureSource("road");
1749: // FeatureStore road2 = (FeatureStore) data.getFeatureSource("road");
1750: //
1751: // road1.setTransaction(t1);
1752: // road2.setTransaction(t2);
1753: //
1754: // Feature feature;
1755: // Feature[] ORIGIONAL = roadFeatures;
1756: // Feature[] REMOVE = new Feature[ORIGIONAL.length - 1];
1757: // Feature[] ADD = new Feature[ORIGIONAL.length + 1];
1758: // Feature[] FINAL = new Feature[ORIGIONAL.length];
1759: // int i;
1760: // int index;
1761: // index = 0;
1762: //
1763: // for (i = 0; i < ORIGIONAL.length; i++) {
1764: // feature = ORIGIONAL[i];
1765: // LOGGER.info("id is " + feature.getID());
1766: //
1767: // if (!feature.getID().equals("road.rd1")) {
1768: // REMOVE[index++] = feature;
1769: // }
1770: // }
1771: //
1772: // for (i = 0; i < ORIGIONAL.length; i++) {
1773: // ADD[i] = ORIGIONAL[i];
1774: // }
1775: //
1776: // ADD[i] = newRoad;
1777: //
1778: // for (i = 0; i < REMOVE.length; i++) {
1779: // FINAL[i] = REMOVE[i];
1780: // }
1781: //
1782: // FINAL[i] = newRoad;
1783: //
1784: // // start of with ORIGINAL
1785: // assertTrue(covers(road.getFeatures().reader(), ORIGIONAL));
1786: //
1787: // // road1 removes road.rd1 on t1
1788: // // -------------------------------
1789: // // - tests transaction independence from DataStore
1790: // road1.removeFeatures(rd1Filter);
1791: //
1792: // // still have ORIGIONAL and t1 has REMOVE
1793: // assertTrue(covers(road.getFeatures().reader(), ORIGIONAL));
1794: // assertTrue(covers(road1.getFeatures().reader(), REMOVE));
1795: //
1796: // // road2 adds road.rd4 on t2
1797: // // ----------------------------
1798: // // - tests transaction independence from each other
1799: // FeatureReader reader = DataUtilities.reader(new Feature[] { newRoad, });
1800: // road2.addFeatures(reader);
1801: //
1802: // // We still have ORIGIONAL, t1 has REMOVE, and t2 has ADD
1803: // assertTrue(covers(road.getFeatures().reader(), ORIGIONAL));
1804: // assertTrue(covers(road1.getFeatures().reader(), REMOVE));
1805: // assertTrue(coversLax(road2.getFeatures().reader(), ADD));
1806: //
1807: // // commit t1
1808: // // ---------
1809: // // -ensure that delayed writing of transactions takes place
1810: // //
1811: // t1.commit();
1812: //
1813: // // We now have REMOVE, as does t1 (which has not additional diffs)
1814: // // t2 will have FINAL
1815: // assertTrue(covers(road.getFeatures().reader(), REMOVE));
1816: // assertTrue(covers(road1.getFeatures().reader(), REMOVE));
1817: // assertTrue(coversLax(road2.getFeatures().reader(), FINAL));
1818: //
1819: // // commit t2
1820: // // ---------
1821: // // -ensure that everyone is FINAL at the end of the day
1822: // t2.commit();
1823: //
1824: // // We now have Number( remove one and add one)
1825: // assertTrue(coversLax(road.getFeatures().reader(), FINAL));
1826: // assertTrue(coversLax(road1.getFeatures().reader(), FINAL));
1827: // assertTrue(coversLax(road2.getFeatures().reader(), FINAL));
1828: // }
1829:
1830: boolean isLocked(String typeName, String fid) {
1831: InProcessLockingManager lockingManager = (InProcessLockingManager) data
1832: .getLockingManager();
1833:
1834: return lockingManager.isLocked(typeName, fid);
1835: }
1836:
1837: //
1838: // FeatureLocking Testing
1839: //
1840:
1841: /*
1842: * Test for void lockFeatures()
1843: */
1844: public void testLockFeatures() throws IOException {
1845: FeatureLock lock = FeatureLockFactory.generate("test",
1846: LOCK_DURATION);
1847: FeatureLocking road = (FeatureLocking) data
1848: .getFeatureSource("road");
1849: road.setFeatureLock(lock);
1850:
1851: assertFalse(isLocked("road", "road.rd1"));
1852: road.lockFeatures();
1853: assertTrue(isLocked("road", "road.rd1"));
1854: }
1855:
1856: public void testUnLockFeatures() throws IOException {
1857: FeatureLock lock = FeatureLockFactory.generate("test",
1858: LOCK_DURATION);
1859: FeatureLocking road = (FeatureLocking) data
1860: .getFeatureSource("road");
1861: road.setFeatureLock(lock);
1862: road.lockFeatures();
1863:
1864: try {
1865: road.unLockFeatures();
1866: fail("unlock should fail due on AUTO_COMMIT");
1867: } catch (IOException expected) {
1868: }
1869:
1870: Transaction t = new DefaultTransaction();
1871: road.setTransaction(t);
1872:
1873: try {
1874: road.unLockFeatures();
1875: fail("unlock should fail due lack of authorization");
1876: } catch (IOException expected) {
1877: }
1878:
1879: t.addAuthorization(lock.getAuthorization());
1880: road.unLockFeatures();
1881: t.close();
1882: }
1883:
1884: public void testLockFeatureInteraction() throws IOException {
1885: FeatureLock lockA = FeatureLockFactory.generate("LockA",
1886: LOCK_DURATION);
1887: FeatureLock lockB = FeatureLockFactory.generate("LockB",
1888: LOCK_DURATION);
1889: Transaction t1 = new DefaultTransaction();
1890: Transaction t2 = new DefaultTransaction();
1891: FeatureLocking road1 = (FeatureLocking) data
1892: .getFeatureSource("road");
1893: FeatureLocking road2 = (FeatureLocking) data
1894: .getFeatureSource("road");
1895: road1.setTransaction(t1);
1896: road2.setTransaction(t2);
1897: road1.setFeatureLock(lockA);
1898: road2.setFeatureLock(lockB);
1899:
1900: assertFalse(isLocked("road", "road.rd1"));
1901: assertFalse(isLocked("road", "road.rd2"));
1902: assertFalse(isLocked("road", "road.rd3"));
1903:
1904: road1.lockFeatures(rd1Filter);
1905: assertTrue(isLocked("road", "road.rd1"));
1906: assertFalse(isLocked("road", "road.rd2"));
1907: assertFalse(isLocked("road", "road.rd3"));
1908:
1909: road2.lockFeatures(rd2Filter);
1910: assertTrue(isLocked("road", "road.rd1"));
1911: assertTrue(isLocked("road", "road.rd2"));
1912: assertFalse(isLocked("road", "road.rd3"));
1913:
1914: try {
1915: road1.unLockFeatures(rd1Filter);
1916: fail("need authorization");
1917: } catch (IOException expected) {
1918: }
1919:
1920: t1.addAuthorization(lockA.getAuthorization());
1921:
1922: try {
1923: road1.unLockFeatures(rd2Filter);
1924: fail("need correct authorization");
1925: } catch (IOException expected) {
1926: }
1927:
1928: road1.unLockFeatures(rd1Filter);
1929: assertFalse(isLocked("road", "road.rd1"));
1930: assertTrue(isLocked("road", "road.rd2"));
1931: assertFalse(isLocked("road", "road.rd3"));
1932:
1933: t2.addAuthorization(lockB.getAuthorization());
1934: road2.unLockFeatures(rd2Filter);
1935: assertFalse(isLocked("road", "road.rd1"));
1936: assertFalse(isLocked("road", "road.rd2"));
1937: assertFalse(isLocked("road", "road.rd3"));
1938:
1939: t1.close();
1940: t2.close();
1941: }
1942:
1943: public void testGetFeatureLockingExpire() throws Exception {
1944: FeatureLock lock = FeatureLockFactory.generate("Timed", 1000);
1945:
1946: FeatureLocking road = (FeatureLocking) data
1947: .getFeatureSource("road");
1948: road.setFeatureLock(lock);
1949: assertFalse(isLocked("road", "road.rd1"));
1950:
1951: road.lockFeatures(rd1Filter);
1952: assertTrue(isLocked("road", "road.rd1"));
1953: long then = System.currentTimeMillis();
1954: do {
1955: Thread.sleep(1000);
1956: } while (System.currentTimeMillis() - then < 1000);
1957: assertFalse(isLocked("road", "road.rd1"));
1958: }
1959:
1960: public void testOidFidMapper() throws IOException,
1961: IllegalAttributeException {
1962: // get the schema and make sure the FID mapper is an OID one
1963: FIDMapper mapper = ((PostgisDataStore) data)
1964: .getFIDMapper("lake");
1965: FIDMapper base = null;
1966: if (mapper instanceof TypedFIDMapper) {
1967: base = ((TypedFIDMapper) mapper).getWrappedMapper();
1968: } else
1969: base = mapper;
1970:
1971: assertTrue(base instanceof OIDFidMapper);
1972:
1973: // read features from the database, just check we don't crash and that id's are not null
1974: FeatureReader reader = ((PostgisDataStore) data)
1975: .getFeatureReader(data.getSchema("lake"),
1976: Filter.INCLUDE, Transaction.AUTO_COMMIT);
1977:
1978: while (reader.hasNext()) {
1979: Feature f = reader.next();
1980: assertNotNull(f.getID());
1981: }
1982: reader.close();
1983:
1984: FeatureWriter writer = data.getFeatureWriterAppend("lake",
1985: Transaction.AUTO_COMMIT);
1986: SimpleFeature f = (SimpleFeature) writer.next();
1987: Object[] attributes = new Object[f.getNumberOfAttributes()];
1988: f.setAttributes(lakeFeatures[0].getAttributes(attributes));
1989: writer.write();
1990: writer.close();
1991:
1992: String id = f.getID();
1993: assertNotNull(id);
1994: assertTrue(!id.trim().equals(""));
1995: Long.parseLong(id.substring(5)); // make sure it's a number
1996: }
1997:
1998: }
|