Source Code Cross Referenced for VersionedFeatureWriter.java in  » GIS » GeoTools-2.4.1 » org » geotools » data » postgis » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.data.postgis 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2002-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.postgis;
017:
018:        import java.io.IOException;
019:        import java.sql.SQLException;
020:        import java.sql.Statement;
021:
022:        import org.geotools.data.DataSourceException;
023:        import org.geotools.data.DataUtilities;
024:        import org.geotools.data.FeatureListenerManager;
025:        import org.geotools.data.FeatureLockException;
026:        import org.geotools.data.FeatureWriter;
027:        import org.geotools.data.jdbc.JDBCUtils;
028:        import org.geotools.data.jdbc.MutableFIDFeature;
029:        import org.geotools.data.postgis.fidmapper.VersionedFIDMapper;
030:        import org.geotools.feature.AttributeType;
031:        import org.geotools.feature.DefaultFeatureType;
032:        import org.geotools.feature.Feature;
033:        import org.geotools.feature.FeatureType;
034:        import org.geotools.feature.GeometryAttributeType;
035:        import org.geotools.feature.IllegalAttributeException;
036:        import org.geotools.geometry.jts.JTS;
037:        import org.opengis.referencing.crs.CoordinateReferenceSystem;
038:        import org.opengis.referencing.operation.TransformException;
039:
040:        import com.vividsolutions.jts.geom.Envelope;
041:        import com.vividsolutions.jts.geom.Geometry;
042:
043:        /**
044:         * A feature writer that handles versioning using two slave feature writers to expire old features
045:         * and create new revisions of the features
046:         * 
047:         * @author aaime
048:         * @since 2.4
049:         * 
050:         */
051:        class VersionedFeatureWriter implements  FeatureWriter {
052:
053:            private static Long NON_EXPIRED = new Long(Long.MAX_VALUE);
054:
055:            private FeatureWriter updateWriter;
056:
057:            private FeatureWriter appendWriter;
058:
059:            private FeatureType featureType;
060:
061:            private Feature oldFeature;
062:
063:            private Feature newFeature;
064:
065:            private Feature liveFeature;
066:
067:            private VersionedJdbcTransactionState state;
068:
069:            private VersionedFIDMapper mapper;
070:
071:            private FeatureListenerManager listenerManager;
072:
073:            private boolean autoCommit;
074:
075:            /**
076:             * Builds a new feature writer
077:             * 
078:             * @param updateWriter
079:             * @param appendWriter
080:             * @param featureType
081:             *            the outside visible feature type
082:             * @param mapper
083:             * @param autoCommit
084:             *            if true, the transaction need to be committed once the writer is closed
085:             */
086:            public VersionedFeatureWriter(FeatureWriter updateWriter,
087:                    FeatureWriter appendWriter, FeatureType featureType,
088:                    VersionedJdbcTransactionState state,
089:                    VersionedFIDMapper mapper, boolean autoCommit) {
090:                this .updateWriter = updateWriter;
091:                this .appendWriter = appendWriter;
092:                this .featureType = featureType;
093:                this .state = state;
094:                this .mapper = mapper;
095:                this .autoCommit = autoCommit;
096:            }
097:
098:            public void setFeatureListenerManager(
099:                    FeatureListenerManager listenerManager) {
100:                this .listenerManager = listenerManager;
101:            }
102:
103:            public void close() throws IOException {
104:                if (updateWriter != null)
105:                    updateWriter.close();
106:                appendWriter.close();
107:
108:                // double check, state.getTransaction() will return null if the transaction
109:                // has already been closed
110:                if (autoCommit && state.getTransaction() != null) {
111:                    state.getTransaction().commit();
112:                    state.getTransaction().close();
113:                }
114:            }
115:
116:            public FeatureType getFeatureType() {
117:                return featureType;
118:            }
119:
120:            public boolean hasNext() throws IOException {
121:                appendWriter.hasNext();
122:                if (updateWriter != null)
123:                    return updateWriter.hasNext();
124:                else
125:                    return false;
126:            }
127:
128:            public Feature next() throws IOException {
129:                Feature original = null;
130:                if (updateWriter != null && updateWriter.hasNext()) {
131:                    oldFeature = updateWriter.next();
132:                    newFeature = appendWriter.next();
133:                    original = oldFeature;
134:                    state
135:                            .expandDirtyBounds(getLatLonFeatureEnvelope(oldFeature));
136:                } else {
137:                    oldFeature = null;
138:                    newFeature = appendWriter.next();
139:                    original = newFeature;
140:                }
141:
142:                try {
143:                    liveFeature = DataUtilities.reType(featureType, original);
144:                    // if the feature it brand new, it'll have a random fid, not a
145:                    // proper one, keep using
146:                    // it, we cannot un-version it
147:                    String unversionedId = liveFeature.getID();
148:                    if (oldFeature != null)
149:                        unversionedId = mapper.getUnversionedFid(liveFeature
150:                                .getID());
151:                    liveFeature = new MutableFIDFeature(
152:                            (DefaultFeatureType) featureType, liveFeature
153:                                    .getAttributes(new Object[featureType
154:                                            .getAttributeCount()]),
155:                            unversionedId);
156:                    return liveFeature;
157:                } catch (IllegalAttributeException e) {
158:                    throw new DataSourceException(
159:                            "Error casting versioned feature to external one. "
160:                                    + "Should not happen, there's a bug at work",
161:                            e);
162:                }
163:            }
164:
165:            /**
166:             * Computes a feature's envelope, using all geometry attributes, and returns an envelop in WGS84
167:             * 
168:             * @param oldFeature
169:             * @return
170:             * @throws TransformException
171:             */
172:            public Envelope getLatLonFeatureEnvelope(Feature feature)
173:                    throws IOException {
174:                try {
175:                    Envelope result = new Envelope();
176:                    FeatureType ft = feature.getFeatureType();
177:                    for (int i = 0; i < ft.getAttributeCount(); i++) {
178:                        AttributeType at = ft.getAttributeType(i);
179:                        if (at instanceof  GeometryAttributeType) {
180:                            GeometryAttributeType gat = (GeometryAttributeType) at;
181:                            CoordinateReferenceSystem crs = gat
182:                                    .getCoordinateSystem();
183:
184:                            Geometry geom = (Geometry) feature.getAttribute(i);
185:                            if (geom != null) {
186:                                Envelope env = geom.getEnvelopeInternal();
187:                                if (crs != null)
188:                                    env = JTS.toGeographic(env, crs);
189:                                result.expandToInclude(env);
190:                            }
191:                        }
192:                    }
193:                    return result;
194:                } catch (TransformException e) {
195:                    throw new DataSourceException(
196:                            "Error computing lat/long envelope of the current feature. "
197:                                    + "This is needed to update the changeset bbox",
198:                            e);
199:                }
200:            }
201:
202:            public void remove() throws IOException {
203:                // if the feature is new, we have nothing to remove
204:                if (oldFeature == null) {
205:                    throw new IOException("No feature available to remove");
206:                }
207:
208:                listenerManager.fireFeaturesRemoved(getFeatureType()
209:                        .getTypeName(), state.getTransaction(), oldFeature
210:                        .getBounds(), false);
211:                writeOldFeature(true);
212:            }
213:
214:            private void writeOldFeature(boolean expire) throws IOException,
215:                    DataSourceException {
216:                try {
217:                    if (expire)
218:                        oldFeature.setAttribute("expired", new Long(state
219:                                .getRevision()));
220:                    updateWriter.write();
221:                } catch (IllegalAttributeException e) {
222:                    throw new DataSourceException(
223:                            "Error writing expiration tag on old feature. "
224:                                    + "Should not happen, there's a bug at work.",
225:                            e);
226:                } catch (FeatureLockException fle) {
227:                    // we have to mangle the id here too
228:                    String unversionedFid = mapper.getUnversionedFid(fle
229:                            .getFeatureID());
230:                    FeatureLockException mangled = new FeatureLockException(fle
231:                            .getMessage(), unversionedFid, fle.getCause());
232:                    throw mangled;
233:                }
234:            }
235:
236:            public void write() throws IOException {
237:                Statement st = null;
238:                try {
239:                    /*
240:                     Ok, this is complex. We have to deal with four separate cases:
241:                     1) the old feature is not there, meaning we're inserting a new feature
242:                     2) the old feature is there, the new feature is equal to the old one -> no changes, 
243:                        let's just move on
244:                     3) the old feature is there, and it's the first time we modify that feature
245:                        in this transactions, meaning we need to expire the old feature, and 
246:                        create a new, non expired one
247:                     4) the old feature is there, but we already modified it during this transaction. This
248:                        means we have to update the old feature 
249:                     */
250:
251:                    boolean dirtyFeature = false;
252:                    if (oldFeature != null) {
253:                        // if there is an old feature, make sure to write a new revision only if the
254:                        // feauture was modified
255:                        boolean dirty = false;
256:                        for (int i = 0; i < liveFeature.getNumberOfAttributes(); i++) {
257:                            AttributeType at = liveFeature.getFeatureType()
258:                                    .getAttributeType(i);
259:                            Object newValue = liveFeature.getAttribute(at
260:                                    .getName());
261:                            Object oldValue = oldFeature.getAttribute(at
262:                                    .getName());
263:                            newFeature.setAttribute(at.getName(), newValue);
264:                            if (!DataUtilities.attributesEqual(newValue,
265:                                    oldValue)) {
266:                                dirty = true;
267:                            }
268:                        }
269:                        if (!dirty)
270:                            return;
271:
272:                        // check if the feature is dirty. The live feature has the right external id
273:                        String typeName = liveFeature.getFeatureType()
274:                                .getTypeName();
275:                        String fid = liveFeature.getID();
276:                        dirtyFeature = state.isFidDirty(typeName, fid);
277:                    }
278:
279:                    Feature writtenFeature = null;
280:                    if (dirtyFeature) {
281:                        // we're updating again a feature we already touched, so we have to move
282:                        // attributes from the live to the old, and make sure the old is not expired
283:                        // (we may have deleted and then re-inserted that feature, if FID are the user
284:                        // assigned kind we can get into troubles with duplicated primary keys)
285:
286:                        // copy attributes from live to new
287:                        for (int i = 0; i < liveFeature.getNumberOfAttributes(); i++) {
288:                            AttributeType at = liveFeature.getFeatureType()
289:                                    .getAttributeType(i);
290:                            oldFeature.setAttribute(at.getName(), liveFeature
291:                                    .getAttribute(at.getName()));
292:                        }
293:
294:                        // write the old one
295:                        writeOldFeature(false);
296:
297:                        writtenFeature = oldFeature;
298:                    } else {
299:                        // expire if needed
300:                        if (oldFeature != null)
301:                            writeOldFeature(true);
302:
303:                        // copy attributes from live to new
304:                        for (int i = 0; i < liveFeature.getNumberOfAttributes(); i++) {
305:                            AttributeType at = liveFeature.getFeatureType()
306:                                    .getAttributeType(i);
307:                            newFeature.setAttribute(at.getName(), liveFeature
308:                                    .getAttribute(at.getName()));
309:                        }
310:
311:                        //set revision and expired,
312:                        newFeature.setAttribute("expired", NON_EXPIRED);
313:                        newFeature.setAttribute("revision", new Long(state
314:                                .getRevision()));
315:
316:                        // mark the feature creation
317:                        if (oldFeature != null) {
318:                            newFeature.setAttribute("created", oldFeature
319:                                    .getAttribute("created"));
320:                        } else {
321:                            newFeature.setAttribute("created", new Long(state
322:                                    .getRevision()));
323:                        }
324:
325:                        // set FID to the old one
326:                        // TODO: check this, I'm not sure this is the proper handling
327:                        String id = null;
328:                        if (oldFeature != null) {
329:                            id = mapper.createVersionedFid(liveFeature.getID(),
330:                                    state.getRevision());
331:                            newFeature.setAttribute("created", oldFeature
332:                                    .getAttribute("created"));
333:                        } else if (!mapper.hasAutoIncrementColumns()) {
334:                            id = mapper.createID(state.getConnection(),
335:                                    newFeature, null);
336:                            newFeature.setAttribute("created", new Long(state
337:                                    .getRevision()));
338:                        }
339:                        // transfer generated id values to the primary key attributes
340:                        if (id != null) {
341:                            ((MutableFIDFeature) newFeature).setID(id);
342:
343:                            Object[] pkatts = mapper.getPKAttributes(id);
344:                            for (int i = 0; i < pkatts.length; i++) {
345:                                newFeature.setAttribute(
346:                                        mapper.getColumnName(i), pkatts[i]);
347:                            }
348:                        }
349:
350:                        // write
351:                        appendWriter.write();
352:
353:                        // if the id is auto-generated, gather it from the db
354:                        if (oldFeature == null
355:                                && mapper.hasAutoIncrementColumns()) {
356:                            st = state.getConnection().createStatement();
357:                            id = mapper.createID(state.getConnection(),
358:                                    newFeature, st);
359:                        }
360:
361:                        // make sure the newly generated id is set into the live
362:                        // feature, and that it's typed, too
363:                        ((MutableFIDFeature) newFeature).setID(id);
364:                        ((MutableFIDFeature) liveFeature).setID(mapper
365:                                .getUnversionedFid(id));
366:
367:                        // mark the fid as dirty
368:                        state.setFidDirty(liveFeature.getFeatureType()
369:                                .getTypeName(), liveFeature.getID());
370:
371:                        writtenFeature = newFeature;
372:                    }
373:
374:                    // update dirty bounds
375:                    state
376:                            .expandDirtyBounds(getLatLonFeatureEnvelope(writtenFeature));
377:
378:                    // and finally notify the user
379:                    if (oldFeature != null) {
380:                        Envelope bounds = oldFeature.getBounds();
381:                        bounds.expandToInclude(liveFeature.getBounds());
382:                        listenerManager.fireFeaturesChanged(getFeatureType()
383:                                .getTypeName(), state.getTransaction(), bounds,
384:                                false);
385:                    } else {
386:                        listenerManager.fireFeaturesAdded(getFeatureType()
387:                                .getTypeName(), state.getTransaction(),
388:                                liveFeature.getBounds(), false);
389:                    }
390:                } catch (IllegalAttributeException e) {
391:                    throw new DataSourceException(
392:                            "Error writing expiration tag on old feature. "
393:                                    + "Should not happen, there's a bug at work.",
394:                            e);
395:                } catch (SQLException e) {
396:                    throw new DataSourceException(
397:                            "Error creating a new statement for primary key generation",
398:                            e);
399:                } finally {
400:                    JDBCUtils.close(st);
401:                }
402:            }
403:
404:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.