/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2003-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.data;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.geotools.data.Transaction.State;
import org.geotools.factory.Hints;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.feature.GeometryAttribute;
import org.opengis.feature.IllegalAttributeException;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.identity.FeatureId;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Geometry;
/**
* A Transaction.State that keeps a difference table for use with
* AbstractDataStore.
*
* @author Jody Garnett, Refractions Research
*
*
* @source $URL$
*/
public class TransactionStateDiff implements State {
/**
* DataStore used to commit() results of this transaction.
*
* @see TransactionStateDiff.commit();
*/
AbstractDataStore store;
/** Tranasction this State is opperating against. */
Transaction transaction;
/**
* Map of differences by typeName.
*
*
* Differences are stored as a Map of Feature by fid, and are reset during
* a commit() or rollback().
*
*/
Map typeNameDiff = new HashMap();
public TransactionStateDiff(AbstractDataStore dataStore) {
store = dataStore;
}
public synchronized void setTransaction(Transaction transaction) {
if (transaction != null) {
// configure
this.transaction = transaction;
} else {
this.transaction = null;
if (typeNameDiff != null) {
for (Iterator i = typeNameDiff.values().iterator();
i.hasNext();) {
Diff diff = (Diff) i.next();
diff.clear();
}
typeNameDiff.clear();
}
store = null;
}
}
public synchronized Diff diff(String typeName) throws IOException {
if (!exists(typeName)) {
throw new IOException(typeName + " not defined");
}
if (typeNameDiff.containsKey(typeName)) {
return (Diff) typeNameDiff.get(typeName);
} else {
Diff diff = new Diff();
typeNameDiff.put(typeName, diff);
return diff;
}
}
boolean exists(String typeName) {
String[] types;
try {
types = store.getTypeNames();
} catch (IOException e) {
return false;
}
Arrays.sort(types);
return Arrays.binarySearch(types, typeName) != -1;
}
/**
* @see org.geotools.data.Transaction.State#addAuthorization(java.lang.String)
*/
public synchronized void addAuthorization(String AuthID)
throws IOException {
// not required for TransactionStateDiff
}
/**
* Will apply differences to store.
*
* @see org.geotools.data.Transaction.State#commit()
*/
public synchronized void commit() throws IOException {
Map.Entry entry;
for (Iterator> i = typeNameDiff.entrySet().iterator(); i.hasNext();) {
entry = i.next();
String typeName = entry.getKey();
Diff diff = entry.getValue();
applyDiff(typeName, diff);
}
}
/**
* Called by commit() to apply one set of diff
*
*
* The provided will be modified as the differences are applied,
* If the operations are all successful diff will be empty at
* the end of this process.
*
*
*
* diff can be used to represent the following operations:
*
*
*
*
* fid|null: represents a fid being removed
*
*
*
* fid|feature: where fid exists, represents feature modification
*
*
* fid|feature: where fid does not exist, represents feature being modified
*
* Constructs a DiffFeatureReader that works against this Transaction.
*
*
* @param typeName TypeName to aquire a Reader on
*
* @return FeatureReader the mask orgional contents with against the
* current Differences recorded by the Tansasction State
*
* @throws IOException If typeName is not Manged by this Tansaction State
*/
public synchronized FeatureReader reader(String typeName)
throws IOException {
Diff diff = diff(typeName);
FeatureReader reader = store.getFeatureReader(typeName);
return new DiffFeatureReader(reader, diff);
}
/**
* Convience Method for a Transaction based FeatureWriter
*
*
* Constructs a DiffFeatureWriter that works against this Transaction.
*
*
* @param typeName Type Name to record differences against
* @param filter
*
* @return A FeatureWriter that records Differences against a FeatureReader
*
* @throws IOException If a FeatureRader could not be constucted to record
* differences against
*/
public synchronized FeatureWriter writer(final String typeName, Filter filter)
throws IOException {
Diff diff = diff(typeName);
FeatureReader reader = new FilteringFeatureReader(store.getFeatureReader(typeName, new Query(typeName, filter)), filter);
return new DiffFeatureWriter(reader, diff, filter) {
public void fireNotification(int eventType, ReferencedEnvelope bounds) {
switch (eventType) {
case FeatureEvent.FEATURES_ADDED:
store.listenerManager.fireFeaturesAdded(typeName,
transaction, bounds, false);
break;
case FeatureEvent.FEATURES_CHANGED:
store.listenerManager.fireFeaturesChanged(typeName,
transaction, bounds, false);
break;
case FeatureEvent.FEATURES_REMOVED:
store.listenerManager.fireFeaturesRemoved(typeName,
transaction, bounds, false);
break;
}
}
public String toString() {
return "("+reader.toString()+")";
}
};
}
/**
* A NullObject used to represent the absence of a SimpleFeature.
*
* This class is used by TransactionStateDiff as a placeholder
* to represent features that have been removed. The concept
* is generally useful and may wish to be taken out as a separate
* class (used for example to represent deleted rows in a shapefile).
*/
public static final SimpleFeature NULL=new SimpleFeature( ){
public Object getAttribute(String path) {
return null;
}
public Object getAttribute(int index) {
return null;
}
// public Object[] getAttributes(Object[] attributes) {
// return null;
// }
public ReferencedEnvelope getBounds() {
return null;
}
public Geometry getDefaultGeometry() {
return null;
}
public SimpleFeatureType getFeatureType() {
return null;
}
public String getID() {
return null;
}
public FeatureId getIdentifier() {
return null;
}
// public int getNumberOfAttributes() {
// return 0;
// }
public void setAttribute(int position, Object val) {
}
public void setAttribute(String path, Object attribute)
throws IllegalAttributeException {
}
// public void setDefaultGeometry(Geometry geometry)
// throws IllegalAttributeException {
// }
public Object getAttribute(Name name) {
return null;
}
public int getAttributeCount() {
return 0;
}
public List