/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2011, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.data.store; import java.io.IOException; import org.geotools.data.BatchFeatureEvent; import org.geotools.data.Diff; import org.geotools.data.DiffFeatureWriter; import org.geotools.data.FeatureWriter; import org.geotools.data.Transaction; import org.geotools.geometry.jts.ReferencedEnvelope; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; /** * FeatureWriter wrapper that issues events modifications as required. * <p> * It is the responsibility of a FeatureStore to issue events to interested parties as content is modified. The {@link ContentState} keeps track of * the listeners, while {@link EventContentFeatureWriter} is willing to fire the events as needed. * <p> * Event generation happens in two passes: * <ul> * <li>As features are modified events are sent out one at a time</li> * <li>When commit() or rollback() is called a "batch" event is sent out</li> * </ul> * The only trick is the comment() event contains our only indication of the final FeatureIDs generated for new features. The * {@link BatchFeatureEvent} maintains a map of BEFORE/AFTER values allowing any interested party to update their seleciton. * <p> * Please note that if you are using {@link DiffFeatureWriter} it sends out events on its own. * * @author Jody Garnett (LISASoft) * * @source $URL$ */ public class EventContentFeatureWriter implements FeatureWriter<SimpleFeatureType, SimpleFeature> { ContentState state; SimpleFeature feature; // live value supplied by writer ContentFeatureStore store; FeatureWriter<SimpleFeatureType, SimpleFeature> writer; /** * EventContentFeatureWriter construction. * * @param reader * @param diff * @param filter */ public EventContentFeatureWriter(ContentFeatureStore store, FeatureWriter<SimpleFeatureType, SimpleFeature> writer) { this.store = store; this.writer = writer; this.state = store.getState(); Transaction t = state.getTransaction(); if( t != Transaction.AUTO_COMMIT ){ // auto commit does not issue batch events t.putState(this,new EventContentTransactionState()); } } /** * Supplys FeatureTypeFrom reader * * @see org.geotools.data.FeatureWriter#getFeatureType() */ public SimpleFeatureType getFeatureType() { return writer.getFeatureType(); } /** * Next Feature from reader or new content. * * @see org.geotools.data.FeatureWriter#next() */ public SimpleFeature next() throws IOException { if (writer == null) { throw new IOException("FeatureWriter has been closed"); } feature = writer.next(); return feature; } /** * @see org.geotools.data.FeatureWriter#remove() */ public void remove() throws IOException { if (writer == null) { throw new IOException("FeatureWriter has been closed"); } state.fireFeatureRemoved(store, feature); writer.remove(); } /** * Writes out the current feature. * * @throws IOException * * @see org.geotools.data.FeatureWriter#write() */ public void write() throws IOException { if (writer == null) { throw new IOException("FeatureWriter has been closed"); } writer.write(); if (feature == null) { throw new IOException("No feature available to write"); } if (writer.hasNext()) { // modify existing feature ReferencedEnvelope bounds = ReferencedEnvelope.reference(feature.getBounds()); state.fireFeatureUpdated(store, feature, bounds); feature = null; } else { // modify a new feature - ie we are adding something state.fireFeatureAdded(store, feature); } } /** * Query for more content. * * @see org.geotools.data.FeatureWriter#hasNext() */ public boolean hasNext() throws IOException { if (writer == null) { return false; } return writer.hasNext(); } /** * Clean up resources associated with this writer. * * <p> * Diff is not clear()ed as it is assumed that it belongs to a Transaction.State object and may yet be written out. * </p> * * @see org.geotools.data.FeatureWriter#close() */ public void close() throws IOException { Transaction t = state.getTransaction(); if (t != Transaction.AUTO_COMMIT ){ t.removeState(this); } if( writer != null ){ writer.close(); writer = null; } feature = null; } /** * Used to detect commit() and rollback() in order to fire batch feature events. * @author jody * */ class EventContentTransactionState implements Transaction.State { @Override public void commit() throws IOException { store.getState().fireBatchFeatureEvent(true); } @Override public void rollback() throws IOException { store.getState().fireBatchFeatureEvent(false); } @Override public void setTransaction(Transaction transaction) { // not needed to issue batch events (as they pretend to be from AUTO_COMMIT) } @Override public void addAuthorization(String AuthID) throws IOException { // functionality not restricted by lock authorisation } } }