示例#1
0
  /**
   * Tests case where filter is makes use of 2 different attributes but Query object only requests 1
   * of the two attributes. This is a fix for a bug that has occurred.
   */
  @Test
  public void testFeatureReaderWithQuery() throws Exception {
    if (url == null) return;
    Map m = new HashMap();
    m.put(WFSDataStoreFactory.URL.key, url);
    m.put(WFSDataStoreFactory.TIMEOUT.key, new Integer(100000));
    WFS_1_0_0_DataStore wfs = (WFS_1_0_0_DataStore) (new WFSDataStoreFactory()).createDataStore(m);
    FilterFactory2 fac = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());

    Filter filter = fac.equals(fac.property("NAME"), fac.literal("E 58th St"));

    Query query = new Query("tiger:tiger_roads", filter);
    FeatureReader<SimpleFeatureType, SimpleFeature> reader =
        wfs.getFeatureReader(query, new DefaultTransaction());
    int expected = 0;
    while (reader.hasNext()) {
      expected++;
      reader.next();
    }
    query = new Query("tiger:tiger_roads", filter, 100, new String[] {"CFCC"}, "");
    reader = wfs.getFeatureReader(query, new DefaultTransaction());
    int count = 0;
    while (reader.hasNext()) {
      count++;
      reader.next();
    }

    assertEquals(expected, count);
  }
 public SimpleFeature next() throws java.util.NoSuchElementException {
   try {
     return delegate.next();
   } catch (IOException e) {
     throw new RuntimeException(e);
   }
 }
 /* (non-Javadoc)
  * @see java.util.Iterator#next()
  */
 public F next() {
   try {
     return reader.next();
   } catch (Exception e) {
     throw new NoSuchElementException("Exception raised during next: " + e.getLocalizedMessage());
   }
 }
 public Object next() {
   try {
     return delegate.next();
   } catch (IOException e) {
     throw new RuntimeException(e);
   }
 }
示例#5
0
  /**
   * Sets the feature of the source.
   *
   * <p>This method operates by first clearing the contents of the feature store ({@link
   * #removeFeatures(Filter)}), and then obtaining an appending feature writer and writing all
   * features from <tt>reader</tt> to it.
   */
  public final void setFeatures(FeatureReader<SimpleFeatureType, SimpleFeature> reader)
      throws IOException {
    // remove features
    removeFeatures(Filter.INCLUDE);

    // grab a feature writer for insert
    FeatureWriter<SimpleFeatureType, SimpleFeature> writer = getWriter(Filter.INCLUDE, WRITER_ADD);
    try {
      while (reader.hasNext()) {
        SimpleFeature feature = reader.next();

        // grab next feature and populate it
        // JD: worth a note on how we do this... we take a "pull" approach
        // because the raw schema we are inserting into may not match the
        // schema of the features we are inserting
        SimpleFeature toWrite = writer.next();
        for (int i = 0; i < toWrite.getType().getAttributeCount(); i++) {
          String name = toWrite.getType().getDescriptor(i).getLocalName();
          toWrite.setAttribute(name, feature.getAttribute(name));
        }

        // perform the write
        writer.write();
      }
    } finally {
      writer.close();
    }
  }
示例#6
0
  public static void main(String[] args) {
    System.out.println("WFS Demo");
    try {
      //            URL url = new
      // URL("http://www2.dmsolutions.ca/cgi-bin/mswfs_gmap?version=1.0.0&request=getcapabilities&service=wfs");
      URL url = new URL("http://www.refractions.net:8080/geoserver/wfs?REQUEST=GetCapabilities");

      Map m = new HashMap();
      m.put(WFSDataStoreFactory.URL.key, url);
      m.put(WFSDataStoreFactory.TIMEOUT.key, new Integer(10000));
      m.put(WFSDataStoreFactory.PROTOCOL.key, Boolean.FALSE);

      DataStore wfs = (new WFSDataStoreFactory()).createNewDataStore(m);
      Query query = new DefaultQuery(wfs.getTypeNames()[1]);
      FeatureReader<SimpleFeatureType, SimpleFeature> ft =
          wfs.getFeatureReader(query, Transaction.AUTO_COMMIT);
      int count = 0;
      while (ft.hasNext()) if (ft.next() != null) count++;
      System.out.println("Found " + count + " features");
    } catch (IOException e) {
      e.printStackTrace();
    } catch (NoSuchElementException e) {
      e.printStackTrace();
    } catch (IllegalAttributeException e) {
      e.printStackTrace();
    }
  }
  /** @see org.geotools.data.FeatureStore#setFeatures(org.geotools.data.FeatureReader) */
  public void setFeatures(FeatureReader<SimpleFeatureType, SimpleFeature> reader)
      throws IOException {
    WFSTransactionState ts = null;

    if (trans == Transaction.AUTO_COMMIT) {
      ts = new WFSTransactionState(ds);
    } else {
      ts = (WFSTransactionState) trans.getState(ds);
    }

    ts.addAction(
        getSchema().getTypeName(), new DeleteAction(getSchema().getTypeName(), Filter.INCLUDE));

    ReferencedEnvelope bounds = null;
    while (reader.hasNext()) {

      try {
        SimpleFeature f = reader.next();
        List<AttributeDescriptor> atrs = f.getFeatureType().getAttributeDescriptors();
        for (int i = 0; i < atrs.size(); i++) {
          if (atrs.get(i) instanceof GeometryDescriptor) {
            Geometry g = (Geometry) f.getAttribute(i);
            CoordinateReferenceSystem cs =
                ((GeometryDescriptor) atrs.get(i)).getCoordinateReferenceSystem();
            if (cs != null && !cs.getIdentifiers().isEmpty())
              g.setUserData(cs.getIdentifiers().iterator().next().toString());
            if (g == null) continue;
            if (bounds == null) {
              bounds = new ReferencedEnvelope(g.getEnvelopeInternal(), cs);
            } else {
              bounds.expandToInclude(g.getEnvelopeInternal());
            }
          }
        }
        ts.addAction(getSchema().getTypeName(), new InsertAction(f));
      } catch (NoSuchElementException e) {
        WFS_1_0_0_DataStore.LOGGER.warning(e.toString());
      } catch (IllegalAttributeException e) {
        WFS_1_0_0_DataStore.LOGGER.warning(e.toString());
      }
    }

    // Fire a notification.
    // JE
    if (bounds == null) {
      // if bounds are null then send an envelope to say that features were added but
      // at an unknown location.
      bounds = new ReferencedEnvelope(getSchema().getCoordinateReferenceSystem());
      ((WFS_1_0_0_DataStore) getDataStore())
          .listenerManager.fireFeaturesRemoved(
              getSchema().getTypeName(), getTransaction(), bounds, false);
    } else {
      ((WFS_1_0_0_DataStore) getDataStore())
          .listenerManager.fireFeaturesRemoved(
              getSchema().getTypeName(), getTransaction(), bounds, false);
    }
    if (trans == Transaction.AUTO_COMMIT) {
      ts.commit();
    }
  }
  /**
   * @param dataStore A ShapeFileDataStore containing geometries to convert.
   * @param keyAttributes The names of attributes to be concatenated to generate record keys.
   * @throws Exception
   */
  public static void convertFeatures(
      GeometryStreamConverter converter, ShapefileDataStore dataStore, List<String> keyAttributes)
      throws Exception {
    SimpleFeatureType schema = dataStore.getSchema();
    int numFeatures = dataStore.getCount(Query.ALL);
    FeatureReader<SimpleFeatureType, SimpleFeature> reader = null;
    try {
      List<AttributeDescriptor> attrDesc = schema.getAttributeDescriptors();
      String header = "\"the_geom_id\", \"the_geom_key\"";
      for (int i = 1; i < attrDesc.size(); i++) {
        String colName = attrDesc.get(i).getLocalName();
        if (GeometryStreamConverter.debugDBF) header += ", \"" + colName + '"';
        // if any specified attribute matches colName, case insensitive, overwrite specified
        // attribute name with name having correct case
        for (int j = 0; j < keyAttributes.size(); j++)
          if (keyAttributes.get(j).equalsIgnoreCase(colName)) keyAttributes.set(j, colName);
      }
      // debug: read schema and print it out
      if (GeometryStreamConverter.debugDBF) System.out.println(header);

      // loop through features and parse them
      long startTime = System.currentTimeMillis(),
          endTime = startTime,
          debugInterval = 60000,
          nextDebugTime = startTime + debugInterval;
      int featureCount = 0;

      reader = dataStore.getFeatureReader();
      CoordinateReferenceSystem projection = schema.getCoordinateReferenceSystem(); // may be null
      String projectionWKT = projection == null ? null : projection.toWKT();

      while (reader.hasNext()) {
        endTime = System.currentTimeMillis();
        if (GeometryStreamConverter.debugTime && endTime > nextDebugTime) {
          System.out.println(
              String.format(
                  "Processing %s/%s features, %s minutes elapsed",
                  featureCount, numFeatures, (endTime - startTime) / 60000.0));
          while (endTime > nextDebugTime) nextDebugTime += debugInterval;
        }
        convertFeature(converter, reader.next(), keyAttributes, projectionWKT);
        featureCount++;
      }

      if (GeometryStreamConverter.debugTime && endTime - startTime > debugInterval)
        System.out.println(
            String.format(
                "Processing %s features completed in %s minutes",
                numFeatures, (endTime - startTime) / 60000.0));
    } catch (OutOfMemoryError e) {
      e.printStackTrace();
      throw e;
    } finally {
      try {
        if (reader != null) reader.close();
      } catch (IOException e) {
      }
    }
  }
 @Test
 public void testFeatureReaderFidFilter() throws Exception {
   FeatureReader<SimpleFeatureType, SimpleFeature> fr;
   fr = rts.getFeatureReader(new Query(RENAMED, fidFilter), Transaction.AUTO_COMMIT);
   assertEquals(primitive, fr.getFeatureType());
   assertTrue(fr.hasNext());
   SimpleFeature sf = fr.next();
   assertFalse(fr.hasNext());
   fr.close();
   assertEquals(fid, sf.getID());
 }
  public ReferencedEnvelope getBounds() {
    FeatureReader<SimpleFeatureType, SimpleFeature> reader = null;
    try {
      ReferencedEnvelope result = featureSource.getBounds(query);
      if (result != null) {
        return result;
      }

      // ops, we have to compute the results by hand. Let's load just the
      // geometry attributes though
      Query q = new Query(query);
      List<String> geometries = new ArrayList<String>();
      for (AttributeDescriptor ad : getSchema().getAttributeDescriptors()) {
        if (ad instanceof GeometryDescriptor) {
          geometries.add(ad.getLocalName());
        }
      }
      // no geometries, no bounds
      if (geometries.size() == 0) {
        return new ReferencedEnvelope();
      } else {
        q.setPropertyNames(geometries);
      }
      // grab the features and scan through them
      reader = featureSource.getReader(q);
      while (reader.hasNext()) {
        SimpleFeature f = reader.next();
        ReferencedEnvelope featureBounds = ReferencedEnvelope.reference(f.getBounds());
        if (result == null) {
          result = featureBounds;
        } else if (featureBounds != null) {
          result.expandToInclude(featureBounds);
        }
      }
      // return the results if we got any, or return an empty one otherwise
      if (result != null) {
        return result;
      } else {
        return new ReferencedEnvelope(getSchema().getCoordinateReferenceSystem());
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException ex) {
          // we tried...
        }
      }
    }
  }
 public List<FeatureId> addFeatures(final FeatureReader<SimpleFeatureType, SimpleFeature> reader)
     throws IOException {
   List features = new ArrayList();
   while (reader.hasNext()) {
     try {
       SimpleFeature next = reader.next();
       features.add(next);
     } catch (Exception e) {
       throw (IOException) new IOException().initCause(e);
     }
   }
   return addFeatures(
       DataUtilities.collection((SimpleFeature[]) features.toArray(new SimpleFeature[0])));
 }
  @Test
  public void testGetFeaturesReader() throws Exception {
    FeatureReader<SimpleFeatureType, SimpleFeature> fr;
    fr = rts.getFeatureReader(new Query(RENAMED), Transaction.AUTO_COMMIT);
    SimpleFeature sf = fr.next();
    fr.close();

    assertEquals(primitive, sf.getFeatureType());

    // check the feature ids have been renamed as well
    assertTrue(
        "Feature id has not been renamed, it's still " + sf.getID(),
        sf.getID().startsWith(RENAMED));
  }
 protected Set fids(Filter filter)
     throws NoSuchElementException, IOException, IllegalAttributeException {
   Set fids = new HashSet();
   String typeName = getSchema().getTypeName();
   DefaultQuery query =
       new DefaultQuery(typeName, filter, Integer.MAX_VALUE, Query.ALL_NAMES, "fids");
   FeatureReader<SimpleFeatureType, SimpleFeature> reader =
       getJDBCDataStore().getFeatureReader(query, getTransaction());
   try {
     while (reader.hasNext()) {
       fids.add(reader.next().getID());
     }
   } finally {
     reader.close();
   }
   return fids;
 }
 public int size() {
   FeatureReader fr = null;
   try {
     int size = featureSource.getCount(query);
     if (size >= 0) {
       return size;
     } else {
       // we have to iterate, probably best if we do a minimal query that
       // only loads a short attribute
       AttributeDescriptor chosen = null;
       for (AttributeDescriptor ad : getSchema().getAttributeDescriptors()) {
         if (chosen == null || size(ad) < size(chosen)) {
           chosen = ad;
         }
       }
       // build the minimal query
       Query q = new Query(query);
       if (chosen != null) {
         q.setPropertyNames(Collections.singletonList(chosen.getLocalName()));
       }
       // bean counting...
       fr = featureSource.getReader(q);
       int count = 0;
       while (fr.hasNext()) {
         fr.next();
         count++;
       }
       return count;
     }
   } catch (IOException e) {
     throw new RuntimeException(e);
   } finally {
     if (fr != null) {
       try {
         fr.close();
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
     }
   }
 }
 /**
  * Test that a filter query issued.
  *
  * @param filter filter to be passed in the query to determine the subset of features to be
  *     returned, or null for all features
  * @param expectedFeatureIds integer id for returned features, matching the expected row ids
  * @throws Exception
  */
 private void runFilterTest(Filter filter, int[] expectedFeatureIds) throws Exception {
   DataStore datastore = null;
   try {
     datastore = DataStoreFinder.getDataStore(getParams());
     assertNotNull(datastore);
     Query query = new DefaultQuery(TEST_TABLE_NAME, filter);
     FeatureReader<SimpleFeatureType, SimpleFeature> reader = null;
     try {
       /*
        * List of all the integer feature ids seen in the features returned for this query.
        */
       List<Integer> featureIds = new ArrayList<Integer>();
       reader = datastore.getFeatureReader(query, Transaction.AUTO_COMMIT);
       for (SimpleFeature feature = null; reader.hasNext(); ) {
         feature = reader.next();
         /*
          * Convert long feature id of the form test_table_name.1234 to the numeric id
          * used when creating the row. This relies on the behaviour of the postgis fid
          * mapper.
          */
         Integer id = Integer.valueOf(feature.getID().replace(TEST_TABLE_NAME + ".", ""));
         featureIds.add(id);
       }
       /*
        * The query succeeded as expected if and only if the sorted lists of returned and
        * expected ids are equal. The expected ids are converted to a List of Integers to
        * leverage Collections comparison.
        */
       assertEquals(sortedList(expectedFeatureIds), sorted(featureIds));
     } finally {
       if (reader != null) {
         reader.close();
       }
     }
   } finally {
     if (datastore != null) {
       datastore.dispose();
     }
   }
 }
  /**
   * Replace with contents of reader.
   *
   * <p>Equivelent to:
   *
   * <pre><code>
   * FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriter( typeName, false, transaction );
   * Feature feature, newFeature;
   * while( writer.hasNext() ){
   *    feature = writer.next();
   *    writer.remove();
   * }
   * while( reader.hasNext() ){
   *    newFeature = reader.next();
   *    feature = writer.next();
   *    newFeature.setAttributes( feature.getAttributes( null ) );
   *    writer.write();
   * }
   * reader.close();
   * writer.close();
   * </code>
   * </pre>
   *
   * <p>Subclasses may override this method to perform the appropriate optimization for this result.
   *
   * @param reader Contents to replace with
   * @throws IOException
   */
  public void setFeatures(FeatureReader<SimpleFeatureType, SimpleFeature> reader)
      throws IOException {
    String typeName = getSchema().getTypeName();
    FeatureWriter<SimpleFeatureType, SimpleFeature> writer =
        getDataStore().getFeatureWriter(typeName, getTransaction());
    SimpleFeature feature;
    SimpleFeature newFeature;

    try {
      while (writer.hasNext()) {
        feature = writer.next();
        LOGGER.finer("removing feature " + feature);
        writer.remove();
      }

      while (reader.hasNext()) {
        try {
          feature = reader.next();
        } catch (Exception readProblem) {
          throw new DataSourceException(
              "Could not add Features, problem with provided reader", readProblem);
        }

        newFeature = (SimpleFeature) writer.next();

        try {
          newFeature.setAttributes(feature.getAttributes());
        } catch (IllegalAttributeException writeProblem) {
          throw new DataSourceException(
              "Could not create " + typeName + " out of provided feature: " + feature.getID(),
              writeProblem);
        }
        LOGGER.finer("writing feature " + newFeature);
        writer.write();
      }
    } finally {
      reader.close();
      writer.close();
    }
  }
示例#17
0
  /**
   * reads the completechain dataset
   *
   * @throws Exception
   */
  public void getrows() throws Exception {

    // SELECT ... FROM ... WHERE
    //   (statel=state and countyl=county) OR (stater=state and countyr=county )
    FilterFactory ff = FilterFactory.createFilterFactory();

    CompareFilter cf1 = ff.createCompareFilter(FilterType.COMPARE_EQUALS);
    cf1.addLeftValue(ff.createAttributeExpression(null, "statel"));
    cf1.addRightValue(ff.createLiteralExpression(state));

    CompareFilter cf2 = ff.createCompareFilter(FilterType.COMPARE_EQUALS);
    cf2.addLeftValue(ff.createAttributeExpression(null, "countyl"));
    cf2.addRightValue(ff.createLiteralExpression(county));

    LogicFilter and1 = ff.createLogicFilter(cf1, cf2, Filter.LOGIC_AND);

    CompareFilter cf3 = ff.createCompareFilter(FilterType.COMPARE_EQUALS);
    cf3.addLeftValue(ff.createAttributeExpression(null, "stater"));
    cf3.addRightValue(ff.createLiteralExpression(state));

    CompareFilter cf4 = ff.createCompareFilter(FilterType.COMPARE_EQUALS);
    cf4.addLeftValue(ff.createAttributeExpression(null, "countyr"));
    cf4.addRightValue(ff.createLiteralExpression(county));

    LogicFilter and2 = ff.createLogicFilter(cf3, cf4, Filter.LOGIC_AND);

    LogicFilter or = ff.createLogicFilter(and1, and2, Filter.LOGIC_OR);

    String[] ps = new String[] {"wkb_geometry", "statel", "countyl", "stater", "countyr"};
    Query q = new DefaultQuery("county_boundary", or, ps);

    FeatureReader fr = ds.getFeatureReader(q, new DefaultTransaction());

    while (fr.hasNext()) {
      Feature f = fr.next();
      if (!alreadyThere(f.getDefaultGeometry())) lines.add(f.getDefaultGeometry());
    }
    fr.close();
  }
  /**
   * Add Features from reader to this FeatureStore.
   *
   * <p>Equivelent to:
   *
   * <pre><code>
   * Set set = new HashSet();
   * FeatureWriter<SimpleFeatureType, SimpleFeature> writer = dataStore.getFeatureWriter( typeName, true, transaction );
   * Featrue feature, newFeature;
   * while( reader.hasNext() ){
   *    feature = reader.next();
   *    newFeature = writer.next();
   *    newFeature.setAttributes( feature.getAttribtues( null ) );
   *    writer.write();
   *    set.add( newfeature.getID() );
   * }
   * reader.close();
   * writer.close();
   *
   * return set;
   * </code>
   * </pre>
   *
   * <p>(If you don't have a FeatureReader<SimpleFeatureType, SimpleFeature> handy
   * DataUtilities.reader() may be able to help out)
   *
   * <p>Subclasses may override this method to perform the appropriate optimization for this result.
   *
   * @param reader
   * @return The Set of FeatureIDs added
   * @throws IOException
   * @see org.geotools.data.FeatureStore#addFeatures(org.geotools.data.FeatureReader)
   */
  public Set addFeatures(FeatureReader<SimpleFeatureType, SimpleFeature> reader)
      throws IOException {
    Set addedFids = new HashSet();
    String typeName = getSchema().getTypeName();
    SimpleFeature feature = null;
    SimpleFeature newFeature;
    FeatureWriter<SimpleFeatureType, SimpleFeature> writer =
        getDataStore().getFeatureWriterAppend(typeName, getTransaction());

    try {
      while (reader.hasNext()) {
        try {
          feature = reader.next();
        } catch (Exception e) {
          throw new DataSourceException("Could not add Features, problem with provided reader", e);
        }

        newFeature = (SimpleFeature) writer.next();

        try {
          newFeature.setAttributes(feature.getAttributes());
        } catch (IllegalAttributeException writeProblem) {
          throw new DataSourceException(
              "Could not create " + typeName + " out of provided feature: " + feature.getID(),
              writeProblem);
        }

        writer.write();
        addedFids.add(newFeature.getID());
      }
    } finally {
      reader.close();
      writer.close();
    }
    return addedFids;
  }
示例#19
0
  /**
   * Writing test that only engages against a remote geoserver.
   *
   * <p>Makes reference to the standard featureTypes that geoserver ships with. NOTE: Ignoring this
   * test for now because it edits topp:states and GeoServer doesn't return the correct Feature IDs
   * on transactions against shapefiles
   */
  @Test
  @Ignore
  public void testWrite()
      throws NoSuchElementException, IllegalFilterException, IOException,
          IllegalAttributeException {
    if (url == null) return;

    Map m = new HashMap();
    m.put(WFSDataStoreFactory.URL.key, url);
    m.put(WFSDataStoreFactory.TIMEOUT.key, new Integer(10000000));
    DataStore post = (WFS_1_0_0_DataStore) (new WFSDataStoreFactory()).createDataStore(m);
    String typename = TO_EDIT_TYPE;
    SimpleFeatureType ft = post.getSchema(typename);
    SimpleFeatureSource fs = post.getFeatureSource(typename);
    class Watcher implements FeatureListener {
      public int count = 0;

      public void changed(FeatureEvent featureEvent) {
        System.out.println("Event " + featureEvent);
        count++;
      }
    }
    Watcher watcher = new Watcher();
    fs.addFeatureListener(watcher);

    Id startingFeatures = createFidFilter(fs);
    FilterFactory2 filterFac = CommonFactoryFinder.getFilterFactory2(GeoTools.getDefaultHints());
    try {
      GeometryFactory gf = new GeometryFactory();
      MultiPolygon mp =
          gf.createMultiPolygon(
              new Polygon[] {
                gf.createPolygon(
                    gf.createLinearRing(
                        new Coordinate[] {
                          new Coordinate(-88.071564, 37.51099),
                          new Coordinate(-88.467644, 37.400757),
                          new Coordinate(-90.638329, 42.509361),
                          new Coordinate(-89.834618, 42.50346),
                          new Coordinate(-88.071564, 37.51099)
                        }),
                    new LinearRing[] {})
              });
      mp.setUserData("http://www.opengis.net/gml/srs/epsg.xml#" + EPSG_CODE);

      PropertyName geometryAttributeExpression =
          filterFac.property(ft.getGeometryDescriptor().getLocalName());
      PropertyIsNull geomNullCheck = filterFac.isNull(geometryAttributeExpression);
      Query query = new Query(typename, filterFac.not(geomNullCheck), 1, Query.ALL_NAMES, null);
      SimpleFeatureIterator inStore = fs.getFeatures(query).features();

      SimpleFeature f, f2;
      try {
        SimpleFeature feature = inStore.next();

        SimpleFeature copy = SimpleFeatureBuilder.deep(feature);
        SimpleFeature copy2 = SimpleFeatureBuilder.deep(feature);

        f = SimpleFeatureBuilder.build(ft, copy.getAttributes(), null);
        f2 = SimpleFeatureBuilder.build(ft, copy2.getAttributes(), null);
        assertFalse("Max Feature failed", inStore.hasNext());
      } finally {
        inStore.close();
      }

      org.geotools.util.logging.Logging.getLogger("org.geotools.data.wfs").setLevel(Level.FINE);
      SimpleFeatureCollection inserts = DataUtilities.collection(new SimpleFeature[] {f, f2});
      Id fp = WFSDataStoreWriteOnlineTest.doInsert(post, ft, inserts);

      // / okay now count ...
      FeatureReader<SimpleFeatureType, SimpleFeature> count =
          post.getFeatureReader(new Query(ft.getTypeName()), Transaction.AUTO_COMMIT);
      int i = 0;
      while (count.hasNext() && i < 3) {
        f = count.next();
        i++;
      }
      count.close();

      WFSDataStoreWriteOnlineTest.doDelete(post, ft, fp);
      WFSDataStoreWriteOnlineTest.doUpdate(post, ft, ATTRIBUTE_TO_EDIT, NEW_EDIT_VALUE);
      // assertFalse("events not fired", watcher.count == 0);
    } finally {
      try {
        ((SimpleFeatureStore) fs).removeFeatures(filterFac.not(startingFeatures));
      } catch (Exception e) {
        System.out.println(e);
      }
    }
  }
  public void rollback(String toVersion, Filter filter, String[] userIds) throws IOException {
    // TODO: build an optimized version of this that can do the same work with a couple
    // of queries assuming the filter is fully encodable

    Transaction t = getTransaction();
    boolean autoCommit = false;
    if (Transaction.AUTO_COMMIT.equals(t)) {
      t = new DefaultTransaction();
      autoCommit = true;
    }

    // Gather feature modified after toVersion
    ModifiedFeatureIds mfids =
        store.getModifiedFeatureFIDs(schema.getTypeName(), toVersion, null, filter, userIds, t);
    FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);

    // grab the state, we need to mark as dirty all the features we are going to modify/re-insert
    VersionedJdbcTransactionState state = store.wrapped.getVersionedJdbcTransactionState(t);

    // remove all features that have been created and not deleted
    Set fidsToRemove = new HashSet(mfids.getCreated());
    fidsToRemove.removeAll(mfids.getDeleted());
    if (!fidsToRemove.isEmpty()) {
      removeFeatures(store.buildFidFilter(fidsToRemove));
      state.setTypeNameDirty(getSchema().getTypeName());
    }

    // reinstate all features that were there before toVersion and that
    // have been deleted after it. Notice this is an insertion, so to preserve
    // the fids I have to use low level writers where I can set all attributes manually
    // (we work on the assumption the wrapped data store maps all attributes of the primary
    // key in the feature itself)
    Set fidsToRecreate = new HashSet(mfids.getDeleted());
    fidsToRecreate.removeAll(mfids.getCreated());
    if (!fidsToRecreate.isEmpty()) {
      state.setTypeNameDirty(getSchema().getTypeName());
      state.setFidsDirty(getSchema().getTypeName(), fidsToRecreate);

      long revision = store.wrapped.getVersionedJdbcTransactionState(t).getRevision();
      Filter recreateFilter =
          store.buildVersionedFilter(
              schema.getTypeName(), store.buildFidFilter(fidsToRecreate), mfids.fromRevision);
      FeatureReader<SimpleFeatureType, SimpleFeature> fr = null;
      FeatureWriter<SimpleFeatureType, SimpleFeature> fw = null;
      try {
        DefaultQuery q = new DefaultQuery(schema.getTypeName(), recreateFilter);
        fr = store.wrapped.getFeatureReader(q, t);
        fw = store.wrapped.getFeatureWriterAppend(schema.getTypeName(), t);
        while (fr.hasNext()) {
          SimpleFeature original = fr.next();
          SimpleFeature restored = fw.next();
          for (int i = 0; i < original.getFeatureType().getAttributeCount(); i++) {
            restored.setAttribute(i, original.getAttribute(i));
          }
          restored.setAttribute("revision", new Long(revision));
          restored.setAttribute("expired", new Long(Long.MAX_VALUE));
          fw.write();
        }
      } catch (IllegalAttributeException iae) {
        throw new DataSourceException(
            "Unexpected error occurred while " + "restoring deleted featues", iae);
      } finally {
        if (fr != null) fr.close();
        if (fw != null) fw.close();
      }
    }

    // Now onto the modified features, that were there, and still are there.
    // Since we cannot get a sorted writer we have to do a kind of inner loop scan
    // (note, a parellel scan of similarly sorted reader and writer would be more
    // efficient, but writer sorting is not there...)
    // Here it's possible to work against the external API, thought it would be more
    // efficient (but more complex) to work against the wrapped one.
    if (!mfids.getModified().isEmpty()) {
      state.setTypeNameDirty(getSchema().getTypeName());
      state.setFidsDirty(getSchema().getTypeName(), mfids.getModified());

      Filter modifiedIdFilter = store.buildFidFilter(mfids.getModified());
      Filter mifCurrent =
          store.buildVersionedFilter(schema.getTypeName(), modifiedIdFilter, new RevisionInfo());
      FeatureReader<SimpleFeatureType, SimpleFeature> fr = null;
      FeatureWriter<SimpleFeatureType, SimpleFeature> fw = null;
      try {
        fw = store.getFeatureWriter(schema.getTypeName(), mifCurrent, t);
        while (fw.hasNext()) {
          SimpleFeature current = fw.next();
          Filter currIdFilter = ff.id(Collections.singleton(ff.featureId(current.getID())));
          Filter cidToVersion =
              store.buildVersionedFilter(schema.getTypeName(), currIdFilter, mfids.fromRevision);
          DefaultQuery q = new DefaultQuery(schema.getTypeName(), cidToVersion);
          q.setVersion(mfids.fromRevision.toString());
          fr = store.getFeatureReader(q, t);
          SimpleFeature original = fr.next();
          for (int i = 0; i < original.getFeatureType().getAttributeCount(); i++) {
            current.setAttribute(i, original.getAttribute(i));
          }
          fr.close();
          fw.write();
        }
      } catch (IllegalAttributeException iae) {
        throw new DataSourceException(
            "Unexpected error occurred while " + "restoring deleted featues", iae);
      } finally {
        if (fr != null) fr.close();
        if (fw != null) fw.close();
      }
    }

    // if it's auto commit, don't forget to actually commit
    if (autoCommit) {
      t.commit();
      t.close();
    }
  }
 public SimpleFeature next()
     throws IOException, IllegalAttributeException, NoSuchElementException {
   return RetypingFeatureCollection.retype(delegate.next(), builder);
 }
  public FeatureCollection<SimpleFeatureType, SimpleFeature> getLog(
      String fromVersion, String toVersion, Filter filter, String[] userIds, int maxRows)
      throws IOException {
    if (filter == null) filter = Filter.INCLUDE;
    RevisionInfo r1 = new RevisionInfo(fromVersion);
    RevisionInfo r2 = new RevisionInfo(toVersion);

    boolean swapped = false;
    if (r1.revision > r2.revision) {
      // swap them
      RevisionInfo tmpr = r1;
      r1 = r2;
      r2 = tmpr;
      String tmps = toVersion;
      toVersion = fromVersion;
      fromVersion = tmps;
      swapped = true;
    }

    // We implement this exactly as described. Happily, it seems Postgis does not have
    // sql lentgh limitations. Yet, if would be a lot better if we could encode this
    // as a single sql query with subqueries... (but not all filters are encodable...)
    ModifiedFeatureIds mfids =
        store.getModifiedFeatureFIDs(
            schema.getTypeName(), fromVersion, toVersion, filter, userIds, getTransaction());
    Set ids = new HashSet(mfids.getCreated());
    ids.addAll(mfids.getDeleted());
    ids.addAll(mfids.getModified());

    // grab the eventually modified revisions from mfids
    r1 = mfids.fromRevision;
    r2 = mfids.toRevision;

    // no changes?
    if (ids.isEmpty()) return new EmptyFeatureCollection(schema);

    // Create a filter that sounds like:
    // (revision > r1 and revision <= r2) or (expired > r1 and expired <= r2) and fid in
    // (fidlist)
    FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
    Filter fidFilter = store.buildFidFilter(ids);
    Filter transformedFidFilter = store.transformFidFilter(schema.getTypeName(), fidFilter);
    Filter revGrR1 = ff.greater(ff.property("revision"), ff.literal(r1.revision));
    Filter revLeR2 = ff.lessOrEqual(ff.property("revision"), ff.literal(r2.revision));
    Filter expGrR1 = ff.greater(ff.property("expired"), ff.literal(r1.revision));
    Filter expLeR2 = ff.lessOrEqual(ff.property("expired"), ff.literal(r2.revision));
    Filter versionFilter =
        ff.and(transformedFidFilter, ff.or(ff.and(revGrR1, revLeR2), ff.and(expGrR1, expLeR2)));

    // We just want the revision and expired, build a query against the real feature type
    DefaultQuery q =
        new DefaultQuery(schema.getTypeName(), versionFilter, new String[] {"revision", "expired"});
    FeatureReader<SimpleFeatureType, SimpleFeature> fr = null;
    SortedSet revisions = new TreeSet();
    try {
      fr = store.wrapped.getFeatureReader(q, getTransaction());
      while (fr.hasNext()) {
        SimpleFeature f = fr.next();
        Long revision = (Long) f.getAttribute(0);
        if (revision.longValue() > r1.revision) revisions.add(revision);
        Long expired = (Long) f.getAttribute(1);
        if (expired.longValue() != Long.MAX_VALUE && expired.longValue() > r1.revision)
          revisions.add(expired);
      }
    } catch (Exception e) {
      throw new DataSourceException("Error reading modified revisions from datastore", e);
    } finally {
      if (fr != null) fr.close();
    }

    // now, we have a list of revisions between a min and a max
    // let's try to build a fid filter with revisions from the biggest to the smallest
    Set revisionIdSet = new HashSet();
    for (Iterator it = revisions.iterator(); it.hasNext(); ) {
      Long rev = (Long) it.next();
      revisionIdSet.add(
          ff.featureId(VersionedPostgisDataStore.TBL_CHANGESETS + "." + rev.toString()));
    }
    if (revisionIdSet.isEmpty()) return new EmptyFeatureCollection(schema);
    Filter revisionFilter = ff.id(revisionIdSet);

    // return the changelog
    // TODO: sort on revision descending. Unfortunately, to do so we have to fix fid mappers,
    // so that auto-increment can return revision among the attributes, and at the same
    // time simply allow not include fid attributes in the insert queries (or provide a
    // "default"
    // value for them).
    FeatureSource<SimpleFeatureType, SimpleFeature> changesets =
        (FeatureSource<SimpleFeatureType, SimpleFeature>)
            store.getFeatureSource(VersionedPostgisDataStore.TBL_CHANGESETS);
    DefaultQuery sq = new DefaultQuery();
    sq.setFilter(revisionFilter);
    final SortOrder order = swapped ? SortOrder.ASCENDING : SortOrder.DESCENDING;
    sq.setSortBy(new SortBy[] {ff.sort("revision", order)});
    if (maxRows > 0) sq.setMaxFeatures(maxRows);
    return changesets.getFeatures(sq);
  }