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 @ 43978

History | View | Annotate | Download (23.6 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.dal.store.shp;
24

    
25
import java.io.File;
26
import java.io.IOException;
27
import java.util.ArrayList;
28
import java.util.Iterator;
29
import java.util.List;
30

    
31
import org.apache.commons.io.FileUtils;
32
import org.apache.commons.io.FilenameUtils;
33
import org.cresques.cts.ICRSFactory;
34
import org.cresques.cts.IProjection;
35
import org.slf4j.Logger;
36
import org.slf4j.LoggerFactory;
37

    
38
import org.gvsig.fmap.dal.DataStore;
39
import org.gvsig.fmap.dal.DataStoreParameters;
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.FeatureQuery;
52
import org.gvsig.fmap.dal.feature.FeatureSet;
53
import org.gvsig.fmap.dal.feature.FeatureStore;
54
import org.gvsig.fmap.dal.feature.FeatureType;
55
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
56
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
57
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
58
import org.gvsig.fmap.dal.resource.ResourceAction;
59
import org.gvsig.fmap.dal.resource.exception.ResourceException;
60
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
61
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
62
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
63
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
64
import org.gvsig.fmap.dal.resource.file.FileResource;
65
import org.gvsig.fmap.dal.resource.spi.MultiResource;
66
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
67
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
68
import org.gvsig.fmap.dal.store.dbf.DBFStoreParameters;
69
import org.gvsig.fmap.dal.store.dbf.DBFStoreProvider;
70
import org.gvsig.fmap.dal.store.shp.utils.ISHPFile;
71
import org.gvsig.fmap.dal.store.shp.utils.SHP;
72
import org.gvsig.fmap.dal.store.shp.utils.SHPFile2;
73
import org.gvsig.fmap.geom.Geometry;
74
import org.gvsig.fmap.geom.GeometryLocator;
75
import org.gvsig.fmap.geom.GeometryManager;
76
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
77
import org.gvsig.fmap.geom.exception.CreateGeometryException;
78
import org.gvsig.fmap.geom.primitive.Envelope;
79
import org.gvsig.tools.dispose.DisposableIterator;
80
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
81
import org.gvsig.tools.exception.BaseException;
82

    
83
/**
84
 *
85
 */
86
public class SHPStoreProvider extends DBFStoreProvider {
87

    
88
    private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
89
    private static final Logger logger = LoggerFactory.getLogger(SHPStoreProvider.class);
90
    public static String NAME = "Shape";
91
    public static String DESCRIPTION = "Shape file";
92
    private ISHPFile shpFile;
93

    
94
    private MultiResource resource;
95

    
96
    protected static final String GEOMETRY_ATTIBUTE_NAME = "GEOMETRY";
97

    
98
    public static final String METADATA_DEFINITION_NAME = NAME;
99

    
100
    private SHPFeatureWriter writer = null;
101

    
102
    private boolean loTengoEnUso;
103

    
104
    /**
105
     * @param params
106
     * @param storeServices
107
     * @throws InitializeException
108
     */
109
    public SHPStoreProvider(SHPStoreParameters params, DataStoreProviderServices storeServices)
110
        throws InitializeException {
111
        super(params, storeServices, FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME));
112
    }
113

    
114
    protected void init(DBFStoreParameters params, DataStoreProviderServices storeServices) throws InitializeException {
115

    
116
        this.shpFile = new SHPFile2((SHPStoreParameters) params);
117
        super.init(params, storeServices);
118
        this.shpFile.setUseNullGeometry(this.getShpParameters().getUseNullGeometry());
119
    }
120

    
121
    @Override
122
    public SHPStoreParameters getParameters() {
123
        return (SHPStoreParameters) super.getParameters();
124
    }
125

    
126
    @Override
127
    public Object getDynValue(String name) throws DynFieldNotFoundException {
128
        if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
129

    
130
            return this.getShpParameters().getCRS();
131

    
132
        } else if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
133
            try {
134
                return this.shpFile.getFullExtent();
135
            } catch (ReadException e) {
136
                return null;
137
            }
138
        }
139
        return super.getDynValue(name);
140
    }
141

    
142
    protected void initResource(DBFStoreParameters params, DataStoreProviderServices storeServices)
143
        throws InitializeException {
144

    
145
        SHPStoreParameters shpParams = (SHPStoreParameters) params;
146
        resource = (MultiResource) createResource(MultiResource.TYPE_NAME, new Object[] { shpParams.getSHPFileName() });
147

    
148
        resource.addResource(FileResource.NAME, new Object[] { shpParams.getSHPFileName() }, true);
149
        resource.addResource(FileResource.NAME, new Object[] { shpParams.getSHXFileName() }, true);
150
        resource.addResource(FileResource.NAME, new Object[] { shpParams.getDBFFileName() }, true);
151

    
152
        resource.frozen();
153
        resource.addMultiResourceConsumer(this);
154
        super.initResource(resource, storeServices);
155
    }
156

    
157
    ;
158

    
159
    public ResourceProvider getResource() {
160
        return resource;
161
    }
162

    
163
    /**
164
     *
165
     * @throws ResourceNotifyChangesException
166
     */
167
    protected void resourcesNotifyChanges() throws ResourceNotifyChangesException {
168
        getResource().notifyChanges();
169
        // TODO .prj
170

    
171
    }
172

    
173
    /**
174
     * @throws ResourceNotifyCloseException
175
     *
176
     */
177
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
178
        getResource().notifyClose();
179
        // TODO .prj
180

    
181
    }
182

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

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

    
195
    /**
196
     * @throws ResourceNotifyOpenException
197
     *
198
     */
199
    protected void resourcesOpen() throws ResourceNotifyOpenException {
200
        getResource().notifyOpen();
201
    }
202

    
203
    protected static EditableFeatureAttributeDescriptor addGeometryColumn(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
                }
217
            }
218
        }
219

    
220
        if (attr == null) {
221
            String geofield = createGeometryFieldName(fType);
222
            attr = fType.add(geofield, DataTypes.GEOMETRY);
223
            attr.setDefaultValue(null);
224
        }
225

    
226
        attr.setObjectClass(Geometry.class);
227
        attr.setAllowNull(true);
228
        fType.setDefaultGeometryAttributeName(attr.getName());
229
        return attr;
230

    
231
    }
232

    
233
    private static String createGeometryFieldName(FeatureType ft) {
234

    
235
        if (ft.getAttributeDescriptor(GEOMETRY_ATTIBUTE_NAME) == null) {
236
            return GEOMETRY_ATTIBUTE_NAME;
237
        }
238

    
239
        int i = 0;
240
        String candidate = GEOMETRY_ATTIBUTE_NAME + i;
241
        while (ft.getAttributeDescriptor(candidate) != null) {
242
            i++;
243
            candidate = GEOMETRY_ATTIBUTE_NAME + i;
244
        }
245
        return candidate;
246
    }
247

    
248
    protected static FeatureType removeGeometryColumn(EditableFeatureType fType) {
249
        Iterator<?> iter = fType.iterator();
250
        FeatureAttributeDescriptor attr;
251
        while (iter.hasNext()) {
252
            attr = (FeatureAttributeDescriptor) iter.next();
253
            if (attr.getType() == DataTypes.GEOMETRY) {
254
                iter.remove();
255
            }
256
        }
257
        fType.setDefaultGeometryAttributeName(null);
258
        return fType.getNotEditableCopy();
259
    }
260

    
261
    protected EditableFeatureType getTheFeatureType() throws InitializeException, OpenException {
262
        final EditableFeatureType fType = super.getTheFeatureType();
263
        this.open();
264
        try {
265
            getResource().execute(new ResourceAction() {
266

    
267
                public Object run() throws Exception {
268
                    EditableFeatureAttributeDescriptor attr = addGeometryColumn(fType);
269

    
270
                    attr.setGeometryType(geomManager.getGeometryType(
271
                        shpFile.getGeometryType(),
272
                        shpFile.getGeometrySubType()
273
                    ));
274

    
275
                    IProjection srs = getShpParameters().getCRS();
276
                    attr.setSRS(srs);
277

    
278
                    return null;
279
                }
280
            });
281
            return fType;
282
        } catch (ResourceExecuteException e) {
283
            throw new InitializeException(e);
284
        }
285
    }
286

    
287
    protected SHPStoreParameters getShpParameters() {
288
        return (SHPStoreParameters) getParameters();
289
    }
290

    
291
    public String getProviderName() {
292
        return NAME;
293
    }
294

    
295
    public boolean allowWrite() {
296
        return this.shpFile.isEditable() &&
297
            super.allowWrite() &&
298
            !this.getShpParameters().getLoadCorruptGeometriesAsNull() &&
299
            !this.getShpParameters().getAllowInconsistenciesInGeometryType() &&
300
            !this.getShpParameters().getFixLinearRings();
301
    }
302

    
303
    /**
304
     *
305
     * @param index
306
     * @param featureType
307
     * @return
308
     * @throws ReadException
309
     */
310
    protected FeatureProvider getFeatureProviderByIndex(long index, FeatureType featureType) throws DataException {
311
        this.open();
312
        try {
313

    
314
            FeatureProvider featureProvider = super.getFeatureProviderByIndex(index, featureType);
315
            featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
316
            return featureProvider;
317
        } catch (DataException e) {
318
            throw e;
319
        } catch (CreateEnvelopeException e) {
320
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
321
        } catch (CreateGeometryException e) {
322
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
323
        }
324

    
325
    }
326

    
327
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider, long index, FeatureType featureType)
328
        throws DataException {
329
        try {
330
            super.initFeatureProviderByIndex(featureProvider, index, featureType);
331
            featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
332
        } catch (CreateEnvelopeException e) {
333
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
334
        } catch (CreateGeometryException e) {
335
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
336
        }
337
    }
338

    
339
    /**
340
     *
341
     * @param featureProvider
342
     * @throws DataException
343
     */
344
    @Override
345
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider) throws DataException {
346

    
347
        FeatureType featureType = featureProvider.getType();
348
        long index = ((Long) featureProvider.getOID());
349
        boolean hasGeometry = false;
350
        int i = featureType.getDefaultGeometryAttributeIndex();
351
        if (i >= 0) {
352
            if (!featureProvider.isReadOnly(i)) {
353
                Geometry geom;
354
                try {
355
                    geom = this.shpFile.getGeometry(index);
356
                } catch (Exception e) {
357
                    if( this.getShpParameters().getLoadCorruptGeometriesAsNull() ) {
358
                        geom = null;
359
                    } else {
360
                        throw new ReadGeometryException(getName(), featureProvider.getOID(), e);
361
                    }
362
                }
363
                featureProvider.set(i, geom);
364
            }
365
            hasGeometry = true;
366
        }
367
        if (hasDBFAttributes(featureType, hasGeometry)) {
368
            super.loadFeatureProviderByIndex(featureProvider);
369
        }
370

    
371
    }
372

    
373
    public class ReadGeometryException extends ReadException {
374

    
375
        private final static String MESSAGE_FORMAT = "There was errors loading a geometry from '%(store)'.\nCheck 'Load corrupt geometries as null' in the shape's properties of the add layer dialog to skip corrupt geometries. The layer will become read only.";
376
        private final static String MESSAGE_KEY = "_ReadGeometryException";
377
        private static final long serialVersionUID = 2626155328734197112L;
378

    
379
        public ReadGeometryException(String store, Object oid, Throwable cause) {
380
            super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
381
            setValue("store", store);
382
            setValue("storeParameters",getParameters());
383
        }
384
    }
385

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

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

    
409
    public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
410
        FeatureProvider data = new SHPFeatureProvider(this, type);
411
        return data;
412
    }
413

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

    
418
    }
419

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

    
428
    public boolean canWriteGeometry(final int geometryType, int geometrySubType) throws DataException {
429
        this.open();
430
        return ((Boolean) getResource().execute(new ResourceAction() {
431

    
432
            public Object run() throws Exception {
433
                boolean value = shpFile.canWriteGeometry(geometryType);
434
                return value ? Boolean.TRUE : Boolean.FALSE;
435
            }
436
        })).booleanValue();
437
    }
438

    
439
    @SuppressWarnings("rawtypes")
440
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds,
441
        Iterator originalFeatureTypesUpdated) throws PerformEditingException {
442
        final List<Object> originalFeatureTypesUpdatedList = new ArrayList<>();
443
        while (originalFeatureTypesUpdated.hasNext()) {
444
            originalFeatureTypesUpdatedList.add(originalFeatureTypesUpdated.next());
445
        }
446
        
447
        /*
448
         * This will throw an exception if there are new fields
449
         * with names too long
450
         */
451
        checkNewFieldsNameSize(originalFeatureTypesUpdatedList.iterator());
452

    
453
        final FeatureType fType;
454
        try {
455
            fType = this.getStoreServices().getDefaultFeatureType();
456
        } catch (DataException e) {
457
            throw new PerformEditingException(this.getProviderName(), e);
458
        }
459
        // TODO Comprobar el campo de geometria
460
        
461
        final EditableFeatureType dbfFtype = fType.getEditable();
462

    
463
        removeGeometryColumn(dbfFtype);
464

    
465
        try {
466
            // TODO repasar el concepto de enUso de un recurso.
467
            loTengoEnUso = true;
468
            resourceCloseRequest();
469

    
470
            getResource().execute(new ResourceAction() {
471

    
472
                public Object run() throws Exception {
473
                    FeatureSet set = null;
474
                    DisposableIterator iter = null;
475
                    try {
476
                        set = getFeatureStore().getFeatureSet();
477
                        writer = new SHPFeatureWriter(getProviderName());
478

    
479
                        SHPStoreParameters shpParams = getShpParameters();
480
                        SHPStoreParameters tmpParams = (SHPStoreParameters) shpParams.getCopy();
481

    
482
                        File tmp_base = File.createTempFile("tmp_" + System.currentTimeMillis(), null);
483
                        String str_base = tmp_base.getCanonicalPath();
484

    
485
                        tmpParams.setDBFFile(str_base + ".dbf");
486
                        tmpParams.setSHPFile(str_base + ".shp");
487
                        tmpParams.setSHXFile(str_base + ".shx");
488

    
489
                        writer.begin(tmpParams, fType, dbfFtype, set.getSize());
490

    
491
                        iter = set.fastIterator();
492
                        while (iter.hasNext()) {
493
                            Feature feature = (Feature) iter.next();
494
                            writer.append(feature);
495
                        }
496

    
497
                        writer.end();
498
                        loTengoEnUso = false;
499
                        close();
500

    
501

    
502
                        if (!shpParams.getDBFFile().delete()) {
503
                            logger.debug("Can't delete dbf file '" + shpParams.getDBFFile() + "'.");
504
                            throw new IOException("Can't delete dbf '"
505
                                + FilenameUtils.getBaseName(shpParams.getDBFFileName())
506
                                + "' file to replace with the new dbf.\nThe new dbf is in temporary file '" + str_base
507
                                + "'");
508
                        }
509
                        if (!shpParams.getSHPFile().delete()) {
510
                            logger.debug("Can't delete dbf file '" + shpParams.getSHPFile() + "'.");
511
                            throw new IOException("Can't delete shp '"
512
                                + FilenameUtils.getBaseName(shpParams.getSHPFileName())
513
                                + "' file to replace with the new shp.\nThe new shp is in temporary file '" + str_base
514
                                + "'");
515
                        }
516
                        if (!shpParams.getSHXFile().delete()) {
517
                            logger.debug("Can't delete dbf file '" + shpParams.getSHXFile() + "'.");
518
                            throw new IOException("Can't delete shx '"
519
                                + FilenameUtils.getBaseName(shpParams.getSHXFileName())
520
                                + "' file to replace with the new shx.\nThe new shx is in temporary file '" + str_base
521
                                + "'");
522
                        }
523
                        if (shpParams.getCPGFile().exists() && !shpParams.getCPGFile().delete()) {
524
                            logger.debug("Can't delete cpg file '" + shpParams.getCPGFile() + "'.");
525
                            throw new IOException("Can't delete cpg '"
526
                                + FilenameUtils.getBaseName(shpParams.getCPGFileName())
527
                                + "' file to replace with the new cpg.\nThe new cpg is in temporary file '" + str_base
528
                                + "'");
529
                        }
530

    
531
                        File prjFile = SHP.getPrjFile(shpParams.getSHPFile());
532
                        if (prjFile.exists()) {
533
                            if (!prjFile.delete()) {
534
                                logger.debug("Can't delete prj file '" + prjFile + "'.");
535
                                throw new IOException("Can't delete shx '"
536
                                    + FilenameUtils.getBaseName(prjFile.getPath())
537
                                    + "' file to replace with the new shx.\nThe new shx is in temporary file '"
538
                                    + str_base + "'");
539
                            }
540
                        }
541
                        FileUtils.moveFile(tmpParams.getDBFFile(), shpParams.getDBFFile());
542
                        FileUtils.moveFile(tmpParams.getSHPFile(), shpParams.getSHPFile());
543
                        FileUtils.moveFile(tmpParams.getSHXFile(), shpParams.getSHXFile());
544
                        FileUtils.moveFile(tmpParams.getCPGFile(), shpParams.getCPGFile());
545

    
546
                        savePrjFile(shpParams.getFile(), tmpParams.getCRS());
547

    
548
                        resourcesNotifyChanges();
549
                        if (!originalFeatureTypesUpdatedList.isEmpty()) {
550
                             initFeatureType();
551
                        }
552
                       
553
                        return null;
554
                    } finally {
555
                        loTengoEnUso = false;
556
                        dispose(set);
557
                        dispose(iter);
558
                    }
559
                }
560
            });
561

    
562
        } catch (Exception e) {
563
            throw new PerformEditingException(this.getProviderName(), e);
564
        }
565

    
566
    }
567

    
568
    protected void resourceCloseRequest() throws ResourceException {
569
        getResource().closeRequest();
570
    }
571

    
572
    public Envelope getEnvelope() throws DataException {
573
        this.open();
574
        return (Envelope) this.getDynValue("Envelope");
575
    }
576

    
577
    public void append(final FeatureProvider featureProvider) throws DataException {
578
        getResource().execute(new ResourceAction() {
579

    
580
            public Object run() throws Exception {
581
                writer.append(getStoreServices().createFeature(featureProvider));
582
                return null;
583
            }
584
        });
585
    }
586

    
587
    public void beginAppend() throws DataException {
588
        getResource().execute(new ResourceAction() {
589

    
590
            public Object run() throws Exception {
591
                FeatureStore store = getFeatureStore();
592
                FeatureType fType = store.getDefaultFeatureType();
593

    
594
                // TODO Comprobar el campo de geometria
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
    }
607

    
608
    public void endAppend() throws DataException {
609
        getResource().execute(new ResourceAction() {
610

    
611
            public Object run() throws Exception {
612
                writer.end();
613
                close();
614

    
615
                SHPStoreParameters shpParameters = SHPStoreProvider.this.getShpParameters();
616

    
617
                savePrjFile(shpParameters.getFile(), shpParameters.getCRS());
618

    
619
                resourcesNotifyChanges();
620
                return null;
621
            }
622
        });
623
    }
624

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

    
629

    
630
}