001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-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;
017:
018: import java.io.IOException;
019: import java.util.NoSuchElementException;
020:
021: import org.geotools.feature.Feature;
022: import org.geotools.feature.FeatureType;
023: import org.geotools.feature.IllegalAttributeException;
024: import org.opengis.filter.Filter;
025:
026: import com.vividsolutions.jts.geom.Envelope;
027:
028: /**
029: * A FeatureWriter that captures modifications against a FeatureReader.
030: *
031: * <p>
032: * You will eventually need to write out the differences, later.
033: * </p>
034: *
035: * <p>
036: * The api has been implemented in terms of FeatureReader to make explicit that
037: * no Features are writen out by this Class.
038: * </p>
039: *
040: * @author Jody Garnett, Refractions Research
041: *
042: * @see TransactionStateDiff
043: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/data/DiffFeatureWriter.java $
044: */
045: public abstract class DiffFeatureWriter implements FeatureWriter {
046: protected FeatureReader reader;
047: protected Diff diff;
048: Feature next; // next value aquired by hasNext()
049: Feature live; // live value supplied by FeatureReader
050: Feature current; // duplicate provided to user
051:
052: /**
053: * DiffFeatureWriter construction.
054: *
055: * @param reader
056: * @param diff
057: */
058: public DiffFeatureWriter(FeatureReader reader, Diff diff) {
059: this (reader, diff, Filter.INCLUDE);
060: }
061:
062: /**
063: * DiffFeatureWriter construction.
064: *
065: * @param reader
066: * @param diff
067: * @param filter
068: */
069: public DiffFeatureWriter(FeatureReader reader, Diff diff,
070: Filter filter) {
071: this .reader = new DiffFeatureReader(reader, diff, filter);
072: this .diff = diff;
073: }
074:
075: /**
076: * Supplys FeatureTypeFrom reader
077: *
078: * @see org.geotools.data.FeatureWriter#getFeatureType()
079: */
080: public FeatureType getFeatureType() {
081: return reader.getFeatureType();
082: }
083:
084: /**
085: * Next Feature from reader or new content.
086: *
087: * @see org.geotools.data.FeatureWriter#next()
088: */
089: public Feature next() throws IOException {
090: FeatureType type = getFeatureType();
091: if (hasNext()) {
092: // hasNext() will take care recording
093: // any modifications to current
094: try {
095: live = next; // update live value
096: next = null; // hasNext will need to search again
097: current = type.duplicate(live);
098:
099: return current;
100: } catch (IllegalAttributeException e) {
101: throw (IOException) new IOException(
102: "Could not modify content").initCause(e);
103: }
104: } else {
105: // Create new content
106: // created with an empty ID
107: // (The real writer will supply a FID later)
108: try {
109: live = null;
110: next = null;
111: current = type.create(new Object[type
112: .getAttributeCount()], "new" + diff.nextFID);
113: diff.nextFID++;
114: return current;
115: } catch (IllegalAttributeException e) {
116: throw new IOException("Could not create new content");
117: }
118: }
119: }
120:
121: /**
122: * @see org.geotools.data.FeatureWriter#remove()
123: */
124: public void remove() throws IOException {
125: if (live != null) {
126: // mark live as removed
127: diff.remove(live.getID());
128: fireNotification(FeatureEvent.FEATURES_REMOVED, live
129: .getBounds());
130: live = null;
131: current = null;
132: } else if (current != null) {
133: // cancel additional content
134: current = null;
135: }
136: }
137:
138: /**
139: * Writes out the current feature.
140: *
141: * @throws IOException
142: *
143: * @see org.geotools.data.FeatureWriter#write()
144: */
145: public void write() throws IOException {
146: //DJB: I modified this so it doesnt throw an error if you
147: // do an update and you didnt actually change anything.
148: // (We do the work)
149: if ((live != null)) {
150: // We have a modification to record!
151: diff.modify(live.getID(), current);
152:
153: Envelope bounds = new Envelope();
154: bounds.expandToInclude(live.getBounds());
155: bounds.expandToInclude(current.getBounds());
156: fireNotification(FeatureEvent.FEATURES_CHANGED, bounds);
157: live = null;
158: current = null;
159: } else if ((live == null) && (current != null)) {
160: // We have new content to record
161: //
162: diff.add(current.getID(), current);
163: fireNotification(FeatureEvent.FEATURES_ADDED, current
164: .getBounds());
165: current = null;
166: } else {
167: throw new IOException("No feature available to write");
168: }
169: }
170:
171: /**
172: * Query for more content.
173: *
174: * @see org.geotools.data.FeatureWriter#hasNext()
175: */
176: public boolean hasNext() throws IOException {
177: if (next != null) {
178: // we found next already
179: return true;
180: }
181:
182: live = null;
183: current = null;
184:
185: if (reader.hasNext()) {
186: try {
187: next = reader.next();
188: } catch (NoSuchElementException e) {
189: throw new DataSourceException("No more content", e);
190: } catch (IllegalAttributeException e) {
191: throw new DataSourceException("No more content", e);
192: }
193:
194: return true;
195: }
196:
197: return false;
198: }
199:
200: /**
201: * Clean up resources associated with this writer.
202: *
203: * <p>
204: * Diff is not clear()ed as it is assumed that it belongs to a
205: * Transaction.State object and may yet be written out.
206: * </p>
207: *
208: * @see org.geotools.data.FeatureWriter#close()
209: */
210: public void close() throws IOException {
211: if (reader != null) {
212: reader.close();
213: reader = null;
214: }
215:
216: current = null;
217: live = null;
218: next = null;
219: diff = null;
220: }
221:
222: /**
223: * Subclass must provide the notification.
224: *
225: * <p>
226: * Notification requirements for modifications against a Transaction should
227: * only be issued to FeatureSource instances that opperate against the
228: * same typeName and Transaction.
229: * </p>
230: *
231: * <p>
232: * Other FeatureSource instances with the same typeName will be notified
233: * when the Transaction is committed.
234: * </p>
235: *
236: * @param eventType One of FeatureType.FEATURES_ADDED, FeatureType.CHANGED,
237: * FeatureType.FEATURES_REMOVED
238: * @param bounds
239: */
240: protected abstract void fireNotification(int eventType,
241: Envelope bounds);
242: }
|