/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.jdbc; import java.io.IOException; import java.sql.Connection; import java.util.HashMap; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Properties; import javax.sql.DataSource; import org.geotools.data.FeatureReader; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.feature.NameImpl; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.test.OnlineTestCase; import org.opengis.feature.Feature; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import org.opengis.feature.type.AttributeType; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.Name; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Geometry; /** * Test support class for jdbc test cases. * <p> * This test class fires up a live instance of an h2 database to provide a * live database to work with. * </p> * * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org * * * * @source $URL$ */ public abstract class JDBCTestSupport extends OnlineTestCase { static { // uncomment to turn up logging // // java.util.logging.ConsoleHandler handler = new java.util.logging.ConsoleHandler(); // handler.setLevel(java.util.logging.Level.FINE); // // org.geotools.util.logging.Logging.getLogger("org.geotools.data.jdbc").setLevel(java.util.logging.Level.FINE); // org.geotools.util.logging.Logging.getLogger("org.geotools.data.jdbc").addHandler(handler); // // org.geotools.util.logging.Logging.getLogger("org.geotools.jdbc").setLevel(java.util.logging.Level.FINE); // org.geotools.util.logging.Logging.getLogger("org.geotools.jdbc").addHandler(handler); } protected JDBCTestSetup setup; protected JDBCDataStore dataStore; protected SQLDialect dialect; @Override protected Properties createOfflineFixture() { return createTestSetup().createOfflineFixture(); } @Override protected Properties createExampleFixture() { return createTestSetup().createExampleFixture(); } @Override protected String getFixtureId() { return createTestSetup().createDataStoreFactory().getDatabaseID(); } @Override protected boolean isOnline() throws Exception { JDBCTestSetup setup = createTestSetup(); setup.setFixture(fixture); try { DataSource dataSource = setup.getDataSource(); Connection cx = dataSource.getConnection(); cx.close(); return true; } catch (Throwable t) { throw new RuntimeException(t); } finally { try { setup.tearDown(); } catch(Exception e) { System.out.println("Error occurred tearing down the test setup"); } } } @Override protected void connect() throws Exception { //create the test harness if (setup == null) { setup = createTestSetup(); } setup.setFixture(fixture); setup.setUp(); //initialize the database setup.initializeDatabase(); //initialize the data setup.setUpData(); //create the dataStore //TODO: replace this with call to datastore factory HashMap params = new HashMap(); params.put( JDBCDataStoreFactory.NAMESPACE.key, "http://www.geotools.org/test" ); params.put( JDBCDataStoreFactory.SCHEMA.key, "geotools" ); params.put( JDBCDataStoreFactory.DATASOURCE.key, setup.getDataSource() ); JDBCDataStoreFactory factory = setup.createDataStoreFactory(); dataStore = factory.createDataStore( params ); setup.setUpDataStore(dataStore); dialect = dataStore.getSQLDialect(); } protected abstract JDBCTestSetup createTestSetup(); protected void disconnect() throws Exception { setup.tearDown(); dataStore.dispose(); } /** * Returns the table name as the datastore understands it (some datastore are incapable of supporting * mixed case names for example) */ protected String tname( String raw ) { return setup.typeName( raw ); } /** * Returns the attribute name as the datastore understands it (some datastore are incapable of supporting * mixed case names for example) */ protected String aname( String raw ) { return setup.attributeName( raw ); } /** * Returns the attribute name as the datastore understands it (some datastore are incapable of supporting * mixed case names for example) */ protected Name aname( Name raw ) { return new NameImpl( raw.getNamespaceURI(), aname( raw.getLocalPart() ) ); } /** * Checkes the two feature types are equal, taking into consideration the eventual modification * the datastore had to perform in order to actually manage the type (change in names case, for example) */ protected void assertFeatureTypesEqual(SimpleFeatureType expected, SimpleFeatureType actual) { for (int i = 0; i < expected.getAttributeCount(); i++) { AttributeDescriptor expectedAttribute = expected.getDescriptor(i); AttributeDescriptor actualAttribute = actual.getDescriptor(i); assertAttributesEqual(expectedAttribute,actualAttribute); } // make sure the geometry is nillable and has minOccurrs to 0 if(expected.getGeometryDescriptor() != null) { AttributeDescriptor dg = actual.getGeometryDescriptor(); assertTrue(dg.isNillable()); assertEquals(0, dg.getMinOccurs()); } } /** * Checkes the two feature types are equal, taking into consideration the eventual modification * the datastore had to perform in order to actually manage the type (change in names case, for example) */ protected void assertAttributesEqual(AttributeDescriptor expected, AttributeDescriptor actual) { assertEquals(aname(expected.getName()), actual.getName()); assertEquals(expected.getMinOccurs(), actual.getMinOccurs()); assertEquals(expected.getMaxOccurs(), actual.getMaxOccurs()); assertEquals(expected.isNillable(), actual.isNillable()); assertEquals(expected.getDefaultValue(), actual.getDefaultValue()); AttributeType texpected = expected.getType(); AttributeType tactual = actual.getType(); if ( Number.class.isAssignableFrom( texpected.getBinding() ) ) { assertTrue( Number.class.isAssignableFrom( tactual.getBinding() ) ); } else if ( Geometry.class.isAssignableFrom( texpected.getBinding())) { assertTrue( Geometry.class.isAssignableFrom( tactual.getBinding())); } else { assertTrue(texpected.getBinding().isAssignableFrom(tactual.getBinding())); } } protected boolean areCRSEqual(CoordinateReferenceSystem crs1, CoordinateReferenceSystem crs2) { if (crs1==null && crs2==null) return true; if (crs1==null ) return false; return crs1.equals(crs2); } protected boolean areReferencedEnvelopesEuqal(ReferencedEnvelope e1, ReferencedEnvelope e2) { if (e1==null && e2 ==null) return true; if (e1==null || e2 == null) return false; boolean equal = Math.round(e1.getMinX())==Math.round(e2.getMinX()) && Math.round(e1.getMinY())==Math.round(e2.getMinY()) && Math.round(e1.getMaxX())==Math.round(e2.getMaxX()) && Math.round(e1.getMaxY())==Math.round(e2.getMaxY()); if (!equal) return false; return areCRSEqual(e1.getCoordinateReferenceSystem(), e2.getCoordinateReferenceSystem()); } public static interface FeatureAssertion<F extends Feature> { int toIndex(F feature); void check(int index, F feature); } public static interface SimpleFeatureAssertion extends FeatureAssertion<SimpleFeature>{} protected <FT extends FeatureType,F extends Feature> void assertFeatureCollection(int startIndex, int numberExpected, FeatureCollection<FT,F> collection, FeatureAssertion assertion) { assertFeatureIterator(startIndex,numberExpected,collection.features(),assertion); } protected <F extends Feature> void assertFeatureIterator(int startIndex, int numberExpected, FeatureIterator<F> iter, FeatureAssertion assertion) { try { boolean[] loadedFeatures = new boolean[numberExpected]; for (int j = startIndex; j < numberExpected+startIndex; j++) { F feature = iter.next(); assertNotNull(feature); int i = assertion.toIndex(feature); assertTrue(loadedFeatures.length > i-startIndex); assertTrue(i > startIndex-1); assertFalse(loadedFeatures[i-startIndex]); loadedFeatures[i-startIndex] = true; assertion.check(i, feature); } assertFalse(iter.hasNext()); for (int i = 0; i < numberExpected; i++) { assertTrue("feature "+i+" is missing",loadedFeatures[i]); } } finally { iter.close(); } } protected <F extends Feature> void assertFeatureIterator(int startIndex, int numberExpected, final Iterator<F> iterator, FeatureAssertion assertion) { FeatureIterator<F> adapter = new FeatureIterator<F>() { public boolean hasNext() { return iterator.hasNext(); } public F next() { return iterator.next(); } public void close() {} }; assertFeatureIterator(startIndex,numberExpected,adapter,assertion); } protected <FT extends FeatureType,F extends Feature> void assertFeatureReader(int startIndex, int numberExpected, final FeatureReader<FT,F> reader, FeatureAssertion assertion) throws IOException { FeatureIterator<F> iter = new FeatureIterator<F>(){ public boolean hasNext() { try { return reader.hasNext(); } catch (IOException e) { throw new AssertionError(e); } } public F next() throws NoSuchElementException { try { return reader.next(); } catch (IOException e) { throw new AssertionError(e); } } public void close() { try { reader.close(); } catch (IOException e) { throw new AssertionError(e); } } }; assertFeatureIterator(startIndex,numberExpected,iter,assertion); } }