001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.data.store;
017:
018: import java.io.IOException;
019: import java.util.Iterator;
020:
021: import org.geotools.data.DataSourceException;
022: import org.geotools.data.Diff;
023: import org.geotools.data.DiffFeatureReader;
024: import org.geotools.data.DiffFeatureWriter;
025: import org.geotools.data.FeatureEvent;
026: import org.geotools.data.FeatureReader;
027: import org.geotools.data.FeatureWriter;
028: import org.geotools.data.Query;
029: import org.geotools.data.Transaction;
030: import org.geotools.data.TransactionStateDiff;
031: import org.geotools.data.Transaction.State;
032: import org.geotools.feature.Feature;
033: import org.geotools.feature.IllegalAttributeException;
034: import org.geotools.feature.SimpleFeature;
035:
036: import com.vividsolutions.jts.geom.Envelope;
037:
038: /**
039: * A Transaction.State that keeps a difference table.
040: * <p>
041: * This implementation is backed by memory, please feel free to make a scalable
042: * implementation backed by a temporary file.
043: * </p>
044: *
045: * @author Jody Garnett, Refractions Research
046: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/data/store/TypeDiffState.java $
047: */
048: public class TypeDiffState implements State {
049:
050: /** Tranasction this State is opperating against. */
051: Transaction transaction;
052:
053: /**
054: * Map of differences by typeName.
055: *
056: * <p>
057: * Differences are stored as a Map of Feature by fid, and are reset during
058: * a commit() or rollback().
059: * </p>
060: */
061: Diff diffMap = new Diff();
062:
063: private ActiveTypeEntry entry;
064:
065: public TypeDiffState(ActiveTypeEntry typeEntry) {
066: entry = typeEntry;
067: }
068:
069: public synchronized void setTransaction(Transaction transaction) {
070: if (transaction != null) {
071: // configure
072: this .transaction = transaction;
073: } else {
074: this .transaction = null;
075:
076: if (diffMap != null) {
077: diffMap.clear();
078: }
079: entry = null;
080: }
081: }
082:
083: public Diff diff() throws IOException {
084: return diffMap;
085: }
086:
087: /**
088: * @see org.geotools.data.Transaction.State#addAuthorization(java.lang.String)
089: */
090: public synchronized void addAuthorization(String AuthID)
091: throws IOException {
092: // not required for TransactionStateDiff
093: }
094:
095: /**
096: * Will apply differences to store.
097: *
098: * @see org.geotools.data.Transaction.State#commit()
099: */
100: public synchronized void commit() throws IOException {
101: applyDiff(diffMap);
102: }
103:
104: /**
105: * Called by commit() to apply one set of diff
106: *
107: * <p>
108: * diff will be modified as the differneces are applied, If the opperations
109: * is successful diff will be empty at the end of this process.
110: * </p>
111: *
112: * <p>
113: * diff can be used to represent the following operations:
114: * </p>
115: *
116: * <ul>
117: * <li>
118: * fid|null: represents a fid being removed
119: * </li>
120: * <li>
121: * fid|feature: where fid exists, represents feature modification
122: * </li>
123: * <li>
124: * fid|feature: where fid does not exist, represents feature being modified
125: * </li>
126: * </ul>
127: *
128: *
129: * @param typeName typeName being updated
130: * @param diff differences to apply to FeatureWriter
131: *
132: * @throws IOException If the entire diff cannot be writen out
133: * @throws DataSourceException If the entire diff cannot be writen out
134: */
135: void applyDiff(Diff diff) throws IOException {
136: if (diff.isEmpty()) {
137: return;
138: }
139:
140: FeatureWriter writer = entry.createWriter();
141: SimpleFeature feature;
142: Feature update;
143: String fid;
144:
145: try {
146: while (writer.hasNext()) {
147: feature = (SimpleFeature) writer.next();
148: fid = feature.getID();
149:
150: if (diff.modified2.containsKey(fid)) {
151: update = (Feature) diff.modified2.get(fid);
152:
153: if (update == TransactionStateDiff.NULL) {
154: writer.remove();
155:
156: // notify
157: entry.listenerManager.fireFeaturesChanged(entry
158: .getTypeName(), transaction, feature
159: .getBounds(), true);
160: } else {
161: try {
162: feature.setAttributes(update
163: .getAttributes(null));
164: writer.write();
165:
166: // notify
167: Envelope bounds = new Envelope();
168: bounds.expandToInclude(feature.getBounds());
169: bounds.expandToInclude(update.getBounds());
170: entry.listenerManager.fireFeaturesChanged(
171: entry.getTypeName(), transaction,
172: bounds, true);
173: } catch (IllegalAttributeException e) {
174: throw new DataSourceException(
175: "Could update " + fid, e);
176: }
177: }
178: }
179: }
180:
181: Feature addedFeature;
182: SimpleFeature nextFeature;
183:
184: for (Iterator i = diff.added.values().iterator(); i
185: .hasNext();) {
186: addedFeature = (Feature) i.next();
187:
188: fid = addedFeature.getID();
189:
190: nextFeature = (SimpleFeature) writer.next();
191:
192: if (nextFeature == null) {
193: throw new DataSourceException("Could not add "
194: + fid);
195: } else {
196: try {
197: nextFeature.setAttributes(addedFeature
198: .getAttributes(null));
199: writer.write();
200:
201: // notify
202: entry.listenerManager.fireFeaturesAdded(entry
203: .getTypeName(), transaction,
204: nextFeature.getBounds(), true);
205: } catch (IllegalAttributeException e) {
206: throw new DataSourceException("Could update "
207: + fid, e);
208: }
209: }
210: }
211: } finally {
212: writer.close();
213: diff.clear();
214: entry.listenerManager.fireChanged(entry.getTypeName(),
215: transaction, true);
216: }
217: }
218:
219: /**
220: * @see org.geotools.data.Transaction.State#rollback()
221: */
222: public synchronized void rollback() throws IOException {
223: diffMap.clear(); // rollback differences
224: entry.listenerManager.fireChanged(entry.getTypeName(),
225: transaction, false);
226: }
227:
228: /**
229: * Convience Method for a Transaction based FeatureReader.
230: *
231: * <p>
232: * Constructs a DiffFeatureReader that works against this Transaction.
233: * </p>
234: *
235: * @return FeatureReader the mask orgional contents with against the
236: * current Differences recorded by the Tansasction State
237: *
238: * @throws IOException If typeName is not Manged by this Tansaction State
239: */
240: public synchronized FeatureReader reader() throws IOException {
241:
242: return new DiffFeatureReader(entry.reader(Query.ALL,
243: transaction), diffMap);
244: }
245:
246: /**
247: * Convience Method for a Transaction based FeatureWriter
248: *
249: * <p>
250: * Constructs a DiffFeatureWriter that works against this Transaction.
251: * </p>
252: *
253: * @return A FeatureWriter that records Differences against a FeatureReader
254: *
255: * @throws IOException If a FeatureRader could not be constucted to record
256: * differences against
257: */
258: public synchronized FeatureWriter writer() throws IOException {
259: Diff diff = new Diff();
260: FeatureReader reader = entry.createReader();
261:
262: return new DiffFeatureWriter(reader, diff) {
263: protected void fireNotification(int eventType,
264: Envelope bounds) {
265: switch (eventType) {
266: case FeatureEvent.FEATURES_ADDED:
267: entry.listenerManager.fireFeaturesAdded(entry
268: .getTypeName(), transaction, bounds, false);
269:
270: break;
271:
272: case FeatureEvent.FEATURES_CHANGED:
273: entry.listenerManager.fireFeaturesChanged(entry
274: .getTypeName(), transaction, bounds, false);
275:
276: break;
277:
278: case FeatureEvent.FEATURES_REMOVED:
279: entry.listenerManager.fireFeaturesRemoved(entry
280: .getTypeName(), transaction, bounds, false);
281:
282: break;
283: }
284: }
285: };
286: }
287: }
|