Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2058 / libraries / libFMap_dalfile / src / org / gvsig / fmap / dal / store / shp / SHPStoreProvider.java @ 39244

History | View | Annotate | Download (18.5 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22

    
23
/*
24
* AUTHORS (In addition to CIT):
25
* 2008 IVER T.I. S.A.   {{Task}}
26
*/
27

    
28
package org.gvsig.fmap.dal.store.shp;
29

    
30
import java.io.File;
31
import java.io.IOException;
32
import java.util.Iterator;
33

    
34
import org.apache.commons.io.FileUtils;
35
import org.cresques.cts.IProjection;
36
import org.slf4j.Logger;
37
import org.slf4j.LoggerFactory;
38

    
39
import org.gvsig.fmap.dal.DataStore;
40
import org.gvsig.fmap.dal.DataTypes;
41
import org.gvsig.fmap.dal.FileHelper;
42
import org.gvsig.fmap.dal.exception.CloseException;
43
import org.gvsig.fmap.dal.exception.DataException;
44
import org.gvsig.fmap.dal.exception.InitializeException;
45
import org.gvsig.fmap.dal.exception.OpenException;
46
import org.gvsig.fmap.dal.exception.ReadException;
47
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
48
import org.gvsig.fmap.dal.feature.EditableFeatureType;
49
import org.gvsig.fmap.dal.feature.Feature;
50
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
51
import org.gvsig.fmap.dal.feature.FeatureSet;
52
import org.gvsig.fmap.dal.feature.FeatureStore;
53
import org.gvsig.fmap.dal.feature.FeatureType;
54
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
55
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
56
import org.gvsig.fmap.dal.resource.ResourceAction;
57
import org.gvsig.fmap.dal.resource.exception.ResourceException;
58
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
59
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
60
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
61
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
62
import org.gvsig.fmap.dal.resource.file.FileResource;
63
import org.gvsig.fmap.dal.resource.spi.MultiResource;
64
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
65
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
66
import org.gvsig.fmap.dal.store.dbf.DBFStoreParameters;
67
import org.gvsig.fmap.dal.store.dbf.DBFStoreProvider;
68
import org.gvsig.fmap.dal.store.shp.utils.SHPFile;
69
import org.gvsig.fmap.geom.Geometry;
70
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
71
import org.gvsig.fmap.geom.GeometryLocator;
72
import org.gvsig.fmap.geom.GeometryManager;
73
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
74
import org.gvsig.fmap.geom.exception.CreateGeometryException;
75
import org.gvsig.fmap.geom.primitive.Envelope;
76
import org.gvsig.fmap.mapcontext.MapContextLocator;
77
import org.gvsig.fmap.mapcontext.MapContextManager;
78
import org.gvsig.tools.dispose.DisposableIterator;
79
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
80
import org.gvsig.tools.exception.BaseException;
81

    
82
public class SHPStoreProvider extends DBFStoreProvider {
83
        private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
84
        private static final Logger logger = LoggerFactory.getLogger(GeometryManager.class);
85
        public static String NAME = "Shape";
86
        public static String DESCRIPTION = "Shape file";
87
        private SHPFile shpFile;
88

    
89
        private MultiResource resource;
90

    
91
        protected static final String GEOMETRY_ATTIBUTE_NAME = "GEOMETRY";
92

    
93
        public static final String METADATA_DEFINITION_NAME = NAME;
94

    
95
        private SHPFeatureWriter writer = null;
96

    
97
        public SHPStoreProvider(SHPStoreParameters params,
98
                        DataStoreProviderServices storeServices)
99
                        throws InitializeException {
100
                super(
101
                        params, 
102
                        storeServices,
103
                        FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
104
                );
105
        }
106

    
107
        protected void init(DBFStoreParameters params,
108
                        DataStoreProviderServices storeServices) throws InitializeException {
109

    
110
                this.shpFile = new SHPFile((SHPStoreParameters) params);
111
                super.init(params, storeServices);
112
        }
113

    
114
        public Object getDynValue(String name) throws DynFieldNotFoundException {
115
                if( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
116
                        String srs =  this.shpFile.getSRSParameters();
117
                        if (srs == null){
118
                            return this.getShpParameters().getCRS();
119
                        }
120
                } else if( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
121
                        try {
122
                                return this.shpFile.getFullExtent();
123
                        } catch (ReadException e) {
124
                                return null;
125
                        }
126
                }
127
                return super.getDynValue(name);
128
        }
129
        
130
        protected void initResource(DBFStoreParameters params,
131
                        DataStoreProviderServices storeServices) throws InitializeException {
132

    
133
                SHPStoreParameters shpParams = (SHPStoreParameters) params;
134
                resource =
135
                                (MultiResource) createResource(MultiResource.TYPE_NAME,
136
                                                new Object[] { shpParams.getSHPFileName() });
137

    
138
                resource.addResource(FileResource.NAME,
139
                                new Object[] { shpParams.getSHPFileName() }, true);
140
                resource.addResource(FileResource.NAME,
141
                                new Object[] { shpParams.getSHXFileName() }, true);
142
                resource.addResource(FileResource.NAME,
143
                                new Object[] { shpParams.getDBFFileName() }, true);
144

    
145
                resource.addConsumer(this);
146
        };
147

    
148
        public ResourceProvider getResource() {
149
                return resource;
150
        }
151

    
152
        /**
153
         *
154
         * @throws ResourceNotifyChangesException
155
         */
156
        protected void resourcesNotifyChanges()
157
                        throws ResourceNotifyChangesException {
158
                // super.resourcesNotifyChanges();
159
                // this.shpResource.notifyChanges();
160
                // this.shxResource.notifyChanges();
161
                getResource().notifyChanges();
162
                // TODO .prj
163

    
164
        }
165

    
166
        /**
167
         * @throws ResourceNotifyCloseException
168
         *
169
         */
170
        protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
171
//                super.resourcesNotifyClose();
172
//                this.shpResource.notifyClose();
173
//                this.shxResource.notifyClose();
174
                getResource().notifyClose();
175
                // TODO .prj
176

    
177
        }
178

    
179
        @Override
180
        protected void doDispose() throws BaseException {
181
                super.doDispose();
182
                getResource().removeConsumer(this);
183
                this.writer = null;
184
                this.shpFile = null;
185
        }
186

    
187
        protected void disposeResource() {
188
                getResource().removeConsumer(this);
189
        }
190

    
191
        /**
192
         * @throws ResourceNotifyOpenException
193
         *
194
         */
195
        protected void resourcesOpen() throws ResourceNotifyOpenException {
196
                // super.resourcesOpen();
197
                // this.shpResource.notifyOpen();
198
                // this.shxResource.notifyOpen();
199
                getResource().notifyOpen();
200
        }
201

    
202
        protected static EditableFeatureAttributeDescriptor addGeometryColumn(
203
                        EditableFeatureType fType) {
204

    
205
                EditableFeatureAttributeDescriptor attrTmp = null;
206
                EditableFeatureAttributeDescriptor attr = null;
207
                Iterator iter = fType.iterator();
208
                while (iter.hasNext()) {
209
                        attrTmp = (EditableFeatureAttributeDescriptor) iter.next();
210
                        if (attrTmp.getType() == DataTypes.GEOMETRY) {
211
                                if (attr != null) {
212
                                        // Two geom fields not allowed
213
                                        fType.remove(attrTmp.getName());
214
                                } else {
215
                                        attr = attrTmp;
216
                                        attr.setName(GEOMETRY_ATTIBUTE_NAME);
217
                                }
218
                        }
219
                }
220

    
221

    
222
                if (attr == null){
223
                        attr = fType.add(
224
                                        GEOMETRY_ATTIBUTE_NAME, DataTypes.GEOMETRY);
225
                        try {
226
                                attr.setDefaultValue(geomManager
227
                                                .createNullGeometry(SUBTYPES.GEOM2D));
228
                        } catch (CreateGeometryException e) {
229
                                logger.error("Error creating the envelope", e);
230
                        }
231
                }
232

    
233
                attr.setObjectClass(Geometry.class);                
234
                fType.setDefaultGeometryAttributeName(attr.getName());
235
                return attr;
236

    
237
        }
238

    
239
        protected static FeatureType removeGeometryColumn(
240
                        EditableFeatureType fType) {
241
                Iterator iter = fType.iterator();
242
                FeatureAttributeDescriptor attr;
243
                while (iter.hasNext()) {
244
                        attr = (FeatureAttributeDescriptor) iter.next();
245
                        if (attr.getType() == DataTypes.GEOMETRY) {
246
                                iter.remove();
247
                        }
248
                }
249
                fType.setDefaultGeometryAttributeName(null);
250
                return fType.getNotEditableCopy();
251
        }
252

    
253
        protected EditableFeatureType getTheFeatureType()
254
                        throws InitializeException, OpenException {
255
                final EditableFeatureType fType = super.getTheFeatureType();
256
                this.open();
257
                // try {
258
                // this.resourcesBegin();
259
                // } catch (DataException e) {
260
                // throw new InitializeException(this.getName(), e);
261
                // }
262
                try {
263
                        getResource().execute(new ResourceAction() {
264
                                public Object run() throws Exception {
265
                                        EditableFeatureAttributeDescriptor attr =
266
                                                        addGeometryColumn(fType);
267
                                        attr.setGeometryType(shpFile.getGeometryType());
268
                                        attr.setGeometrySubType(shpFile.getGeometrySubType());
269

    
270
                                        IProjection srs = getShpParameters().getCRS();
271
                                        if (srs == null) {
272
                                            MapContextManager mcm = MapContextLocator.getMapContextManager();
273
                                                srs = mcm.getDefaultCRS();
274
                                        }
275

    
276
                                        attr.setSRS(srs);
277

    
278
                                        return null;
279
                                }
280
                        });
281
                        return fType;
282
                } catch (ResourceExecuteException e) {
283
                        throw new InitializeException(e);
284
                        // } finally {
285
                        // this.resourcesEnd();
286
                }
287
        }
288

    
289
//        private String getSRSFromPrj(String srsParameters) {
290
//                // TODO identificar que SRS hay que usar, ya sea
291
//                // el que se recibe de los parametros o el que
292
//                // conicida con el que se ha encontrado en el
293
//                // prg... y si ninguna de las dos que?
294
//                return null;
295
//        }
296

    
297
        protected SHPStoreParameters getShpParameters() {
298
                return (SHPStoreParameters) getParameters();
299
        }
300

    
301
        public String getProviderName() {
302
                return NAME;
303
        }
304

    
305
        public boolean allowWrite() {
306
                return this.shpFile.isEditable();
307
        }
308

    
309
        /**
310
         *
311
         * @param index
312
         * @param featureType
313
         * @return
314
         * @throws ReadException
315
         */
316
        protected FeatureProvider getFeatureProviderByIndex(long index,
317
                        FeatureType featureType) throws DataException {
318
                // this.open();
319
                // this.resourcesBegin();
320
                try {
321

    
322
                        FeatureProvider featureProvider = super.getFeatureProviderByIndex(index,
323
                                        featureType);
324
                        featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
325
                        return featureProvider;
326
                } catch (DataException e) {
327
                        throw e;
328
                } catch (CreateEnvelopeException e) {
329
                        throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);                
330
                } catch (CreateGeometryException e) {
331
                    throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
332
        }
333

    
334
        }
335

    
336
        protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
337
                        long index, FeatureType featureType) throws DataException {
338
                // this.open();
339
                // this.resourcesBegin();
340
                try {
341
                        super.initFeatureProviderByIndex(featureProvider, index, featureType);
342
                        featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
343
                } catch (CreateEnvelopeException e) {
344
                        throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);                        
345
                } catch (CreateGeometryException e) {
346
                    throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);       
347
        }
348
        }
349

    
350
        /**
351
         *
352
         * @param featureProvider
353
         * @throws DataException
354
         */
355
        protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
356
                        throws DataException {
357
                // this.open();
358
                // this.resourcesBegin();
359
                // try {
360
                        FeatureType featureType = featureProvider.getType();
361
                        long index = ((Long) featureProvider.getOID()).longValue();
362
                        boolean hasGeometry = false;
363
                        if (featureType.getIndex(featureType.getDefaultGeometryAttributeName()) >= 0) {
364
                                try {
365
                                        featureProvider.setDefaultGeometry(this.shpFile.getGeometry(index));
366
                                        hasGeometry = true;
367
                                } catch (CreateGeometryException e) {
368
                                        throw new ReadException(getProviderName(), e);
369
                                }
370
                        }
371
                        if (hasDBFAttributes(featureType, hasGeometry)) {
372
                                super.loadFeatureProviderByIndex(featureProvider);
373
                        }
374

    
375
                // } finally {
376
                // this.resourcesEnd();
377
                // }
378

    
379
        }
380

    
381
        private boolean hasDBFAttributes(FeatureType featureType,
382
                        boolean hasGeometry) {
383
                FeatureAttributeDescriptor[] attributes =
384
                                featureType.getAttributeDescriptors();
385
                // If there aren't any attributes, nor has any DBF attributes
386
                if (attributes == null || attributes.length == 0) {
387
                        return false;
388
                }
389
                // If there is only one attribute and it is the geometry one
390
                if (attributes.length == 1 && hasGeometry) {
391
                        return false;
392
                }
393
                // In any other case
394
                return true;
395
        }
396

    
397
        protected void loadValue(FeatureProvider featureProvider, int rowIndex,
398
                        FeatureAttributeDescriptor descriptor) throws ReadException {
399
                if (descriptor.getType() == DataTypes.GEOMETRY) {
400
                        return;
401
                } else {
402
                        super.loadValue(featureProvider, rowIndex, descriptor);
403
                }
404
        }
405

    
406
        public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
407
                FeatureProvider data = new SHPFeatureProvider(this, type);
408
                return data;
409
        }
410

    
411

    
412
        protected void openFile() throws IOException, DataException {
413
                super.openFile();
414
                this.shpFile.open();
415

    
416
        }
417

    
418
        protected void closeFile() throws CloseException {
419
                super.closeFile();
420
                if (!this.shpFile.isOpen()) {
421
                        return;
422
                }
423
                this.shpFile.close();
424
        }
425

    
426
        public boolean canWriteGeometry(final int geometryType, int geometrySubType)
427
                        throws DataException {
428
                this.open();
429
                return ((Boolean) getResource().execute(new ResourceAction() {
430
                        public Object run() throws Exception {
431
                                boolean value = shpFile.canWriteGeometry(geometryType);
432
                                return value ? Boolean.TRUE : Boolean.FALSE;
433
                        }
434
                })).booleanValue();
435
//                this.resourcesBegin();
436
//                try {
437
//                        return this.shpFile.canWriteGeometry(geometryType);
438
//
439
//                } finally {
440
//                        this.resourcesEnd();
441
//                }
442
        }
443

    
444
        public void performChanges(Iterator deleteds, Iterator inserteds,
445
                        Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
446
                final FeatureType fType;
447
                try {
448
                        fType = this.getStoreServices().getDefaultFeatureType();
449
                } catch (DataException e) {
450
                        throw new PerformEditingException(this.getProviderName(), e);
451
                }
452
                // TODO Comprobar el campo de geometria
453

    
454
                final EditableFeatureType dbfFtype = fType.getEditable();
455

    
456
                removeGeometryColumn(dbfFtype);
457

    
458
                // try {
459
                // this.resourcesBegin();
460
                // } catch (ResourceExecuteException e1) {
461
                // throw new PerformEditingException(this.getName(), e1);
462
                // }
463

    
464
                try {
465

    
466
                        getResource().execute(new ResourceAction() {
467
                                public Object run() throws Exception {
468
                                        FeatureSet set = null;
469
                                        DisposableIterator iter = null;
470
                                        try {
471
                                                set = getFeatureStore().getFeatureSet();
472
                                                writer = new SHPFeatureWriter(getProviderName());
473

    
474
                                                SHPStoreParameters shpParams = getShpParameters();
475
                                                SHPStoreParameters tmpParams =
476
                                                                (SHPStoreParameters) shpParams.getCopy();
477
                                                
478
                                                File tmp_base = File.createTempFile(
479
                                                    "tmp_" + System.currentTimeMillis(), null);
480
                                                String str_base = tmp_base.getCanonicalPath();
481
                                                
482
                                                tmpParams.setDBFFile(str_base + ".dbf");
483
                                                tmpParams.setSHPFile(str_base + ".shp");
484
                                                tmpParams.setSHXFile(str_base + ".shx");
485

    
486
                                                writer.begin(tmpParams, fType, dbfFtype, set.getSize());
487

    
488
                                                iter = set.fastIterator();
489
                                                while (iter.hasNext()) {
490
                                                        Feature feature = (Feature) iter.next();
491
                                                        writer.append(feature);
492
                                                }
493

    
494
                                                writer.end();
495

    
496
                                                close();
497
                                                resourceCloseRequest();
498

    
499
                                                if (!shpParams.getDBFFile().delete()) {
500
                                                        throw new PerformEditingException(getProviderName(),
501
                                                                        new IOException(shpParams.getDBFFileName()));
502
                                                }
503
                                                if (!shpParams.getSHPFile().delete()) {
504
                                                        throw new PerformEditingException(getProviderName(),
505
                                                                        new IOException(shpParams.getSHPFileName()));
506
                                                }
507
                                                if (!shpParams.getSHXFile().delete()) {
508
                                                        throw new PerformEditingException(getProviderName(),
509
                                                                        new IOException(shpParams.getSHXFileName()));
510
                                                }
511
                                                
512
                                                if (!tmpParams.getDBFFile().renameTo(
513
                                                                shpParams.getDBFFile())) {
514
                                                    logger.info("Warning: copying tmp file instead of renaming: "
515
                                                        + shpParams.getDBFFile());
516
                                                    FileUtils.copyFile(
517
                                                        tmpParams.getDBFFile(),
518
                                                        shpParams.getDBFFile());
519
                                                }
520
                                                if (!tmpParams.getSHPFile().renameTo(
521
                                                                shpParams.getSHPFile())) {
522
                            logger.info("Warning: copying tmp file instead of renaming: "
523
                                + shpParams.getSHPFile());
524
                            FileUtils.copyFile(
525
                                tmpParams.getSHPFile(),
526
                                shpParams.getSHPFile());
527
                                                }
528
                                                if (!tmpParams.getSHXFile().renameTo(
529
                                                                shpParams.getSHXFile())) {
530
                            logger.info("Warning: copying tmp file instead of renaming: "
531
                                + shpParams.getSHXFile());
532
                            FileUtils.copyFile(
533
                                tmpParams.getSHXFile(),
534
                                shpParams.getSHXFile());
535
                                                }
536

    
537
                                                resourcesNotifyChanges();
538
                                                initFeatureType();
539
                                                return null;
540
                                        } finally {
541
                                                dispose(set);
542
                                                dispose(iter);
543
                                        }
544
                                }
545
                        });
546

    
547
                } catch (Exception e) {
548
                        throw new PerformEditingException(this.getProviderName(), e);
549
                        // } finally {
550
                        // this.resourcesEnd();
551
                }
552

    
553

    
554
        }
555

    
556
        protected void resourceCloseRequest() throws ResourceException {
557
                // super.resourceCloseRequest();
558
                // this.shpResource.closeRequest();
559
                // this.shxResource.closeRequest();
560
                getResource().closeRequest();
561
        }
562

    
563
        public Envelope getEnvelope() throws DataException {
564
                this.open();
565
                return (Envelope) this.getDynValue("Envelope");
566
        }
567

    
568
        public void append(final FeatureProvider featureProvider) throws DataException {
569
//                this.resourcesBegin();
570
//                try {
571

    
572
                getResource().execute(new ResourceAction() {
573
                        public Object run() throws Exception {
574
                                writer.append(getStoreServices().createFeature(featureProvider));
575
                                return null;
576
                        }
577
                });
578
//                } finally {
579
//                        this.resourcesEnd();
580
//                }
581

    
582
        }
583

    
584
        public void beginAppend() throws DataException {
585
                // this.resourcesBegin();
586
                // try {
587

    
588
                getResource().execute(new ResourceAction() {
589
                        public Object run() throws Exception {
590
                                FeatureStore store = getFeatureStore();
591
                                FeatureType fType = store.getDefaultFeatureType();
592

    
593
                                // TODO Comprobar el campo de geometria
594

    
595
                                EditableFeatureType dbfFtype = fType.getEditable();
596

    
597
                                removeGeometryColumn(dbfFtype);
598
                                FeatureSet set = store.getFeatureSet();
599

    
600
                                writer = new SHPFeatureWriter(getProviderName());
601

    
602
                                writer.begin(getShpParameters(), fType, dbfFtype, set.getSize());
603
                                return null;
604
                        }
605
                });
606
                // } finally {
607
                // this.resourcesEnd();
608
                // }
609

    
610
        }
611

    
612
        public void endAppend() throws DataException {
613
//                this.resourcesBegin();
614
//                try {
615
                getResource().execute(new ResourceAction() {
616
                        public Object run() throws Exception {
617
                                writer.end();
618
                                resourcesNotifyChanges();
619
                                return null;
620
                        }
621
                });
622
//                } finally {
623
//                        this.resourcesEnd();
624
//                }
625

    
626
        }
627

    
628
        public Object getSourceId() {
629
                return this.getShpParameters().getFile();
630
        }
631
}