Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.shp / src / main / java / org / gvsig / fmap / dal / store / shp / SHPStoreProvider.java @ 40435

History | View | Annotate | Download (18.3 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.tools.dispose.DisposableIterator;
77
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
78
import org.gvsig.tools.exception.BaseException;
79

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

    
87
        private MultiResource resource;
88

    
89
        protected static final String GEOMETRY_ATTIBUTE_NAME = "GEOMETRY";
90

    
91
        public static final String METADATA_DEFINITION_NAME = NAME;
92

    
93
        private SHPFeatureWriter writer = null;
94

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

    
105
        protected void init(DBFStoreParameters params,
106
                        DataStoreProviderServices storeServices) throws InitializeException {
107

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

    
112
        public Object getDynValue(String name) throws DynFieldNotFoundException {
113
                if( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
114
                    
115
                        /*
116
                         * String srs =  this.shpFile.getSRSParameters();
117
                        if (srs != null){
118
                        // This can be non null but not sure how to handle
119
                        }
120
                        */
121
                        return this.getShpParameters().getCRS();
122
                        
123
                } else if( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
124
                        try {
125
                                return this.shpFile.getFullExtent();
126
                        } catch (ReadException e) {
127
                                return null;
128
                        }
129
                }
130
                return super.getDynValue(name);
131
        }
132
        
133
        protected void initResource(DBFStoreParameters params,
134
                        DataStoreProviderServices storeServices) throws InitializeException {
135

    
136
                SHPStoreParameters shpParams = (SHPStoreParameters) params;
137
                resource =
138
                                (MultiResource) createResource(MultiResource.TYPE_NAME,
139
                                                new Object[] { shpParams.getSHPFileName() });
140

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

    
148
                resource.addConsumer(this);
149
        };
150

    
151
        public ResourceProvider getResource() {
152
                return resource;
153
        }
154

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

    
167
        }
168

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

    
180
        }
181

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

    
190
        protected void disposeResource() {
191
                getResource().removeConsumer(this);
192
        }
193

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

    
205
        protected static EditableFeatureAttributeDescriptor addGeometryColumn(
206
                        EditableFeatureType fType) {
207

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

    
224

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

    
236
                attr.setObjectClass(Geometry.class);                
237
                fType.setDefaultGeometryAttributeName(attr.getName());
238
                return attr;
239

    
240
        }
241

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

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

    
273
                                        IProjection srs = getShpParameters().getCRS();
274
                                        attr.setSRS(srs);
275

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

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

    
295
        protected SHPStoreParameters getShpParameters() {
296
                return (SHPStoreParameters) getParameters();
297
        }
298

    
299
        public String getProviderName() {
300
                return NAME;
301
        }
302

    
303
        public boolean allowWrite() {
304
                return this.shpFile.isEditable();
305
        }
306

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

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

    
332
        }
333

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

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

    
373
                // } finally {
374
                // this.resourcesEnd();
375
                // }
376

    
377
        }
378

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

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

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

    
409

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

    
414
        }
415

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

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

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

    
452
                final EditableFeatureType dbfFtype = fType.getEditable();
453

    
454
                removeGeometryColumn(dbfFtype);
455

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

    
462
                try {
463

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

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

    
484
                                                writer.begin(tmpParams, fType, dbfFtype, set.getSize());
485

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

    
492
                                                writer.end();
493

    
494
                                                close();
495
                                                resourceCloseRequest();
496

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

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

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

    
551

    
552
        }
553

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

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

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

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

    
580
        }
581

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

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

    
591
                                // TODO Comprobar el campo de geometria
592

    
593
                                EditableFeatureType dbfFtype = fType.getEditable();
594

    
595
                                removeGeometryColumn(dbfFtype);
596
                                FeatureSet set = store.getFeatureSet();
597

    
598
                                writer = new SHPFeatureWriter(getProviderName());
599

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

    
608
        }
609

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

    
624
        }
625

    
626
        public Object getSourceId() {
627
                return this.getShpParameters().getFile();
628
        }
629
}