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

History | View | Annotate | Download (23.5 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.Iterator;
28

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

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

    
78
/**
79
 * @author fdiaz
80
 *
81
 */
82
public class SHPStoreProvider extends DBFStoreProvider {
83

    
84
    private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
85
    private static final Logger logger = LoggerFactory.getLogger(GeometryManager.class);
86
    public static String NAME = "Shape";
87
    public static String DESCRIPTION = "Shape file";
88
    private ISHPFile shpFile;
89

    
90
    private MultiResource resource;
91

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

    
94
    public static final String METADATA_DEFINITION_NAME = NAME;
95

    
96
    private SHPFeatureWriter writer = null;
97

    
98
    private boolean loTengoEnUso;
99

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

    
110
    protected void init(DBFStoreParameters params,
111
            DataStoreProviderServices storeServices) throws InitializeException {
112

    
113
        this.shpFile = new SHPFile2((SHPStoreParameters) params);
114
        super.init(params, storeServices);
115
        this.shpFile.setUseNullGeometry(this.getShpParameters().getUseNullGeometry());
116
    }
117

    
118
    public Object getDynValue(String name) throws DynFieldNotFoundException {
119
        if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
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.frozen();
149
        resource.addMultiResourceConsumer(this);
150
    }
151

    
152
    ;
153

    
154
        public ResourceProvider getResource() {
155
        return resource;
156
    }
157

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

    
170
    }
171

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

    
183
    }
184

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

    
193
    protected void disposeResource() {
194
        getResource().removeConsumer(this);
195
    }
196

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

    
208
    protected static EditableFeatureAttributeDescriptor addGeometryColumn(
209
            EditableFeatureType fType) {
210

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

    
227
        if (attr == null) {
228
            String geofield = createGeometryFieldName(fType);
229
            attr = fType.add(geofield, DataTypes.GEOMETRY);
230
            attr.setDefaultValue(null);
231
        }
232

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

    
237
    }
238

    
239
    private static String createGeometryFieldName(FeatureType ft) {
240

    
241
        if (ft.getAttributeDescriptor(GEOMETRY_ATTIBUTE_NAME) == null) {
242
            return GEOMETRY_ATTIBUTE_NAME;
243
        }
244

    
245
        int i = 0;
246
        String candidate = GEOMETRY_ATTIBUTE_NAME + i;
247
        while (ft.getAttributeDescriptor(candidate) != null) {
248
            i++;
249
            candidate = GEOMETRY_ATTIBUTE_NAME + i;
250
        }
251
        return candidate;
252
    }
253

    
254
    protected static FeatureType removeGeometryColumn(
255
            EditableFeatureType fType) {
256
        Iterator iter = fType.iterator();
257
        FeatureAttributeDescriptor attr;
258
        while (iter.hasNext()) {
259
            attr = (FeatureAttributeDescriptor) iter.next();
260
            if (attr.getType() == DataTypes.GEOMETRY) {
261
                iter.remove();
262
            }
263
        }
264
        fType.setDefaultGeometryAttributeName(null);
265
        return fType.getNotEditableCopy();
266
    }
267

    
268
    protected EditableFeatureType getTheFeatureType()
269
            throws InitializeException, OpenException {
270
        final EditableFeatureType fType = super.getTheFeatureType();
271
        this.open();
272
                // try {
273
        // this.resourcesBegin();
274
        // } catch (DataException e) {
275
        // throw new InitializeException(this.getName(), e);
276
        // }
277
        try {
278
            getResource().execute(new ResourceAction() {
279
                public Object run() throws Exception {
280
                    EditableFeatureAttributeDescriptor attr
281
                            = addGeometryColumn(fType);
282
                    attr.setGeometryType(shpFile.getGeometryType());
283
                    attr.setGeometrySubType(shpFile.getGeometrySubType());
284

    
285
                    IProjection srs = getShpParameters().getCRS();
286
                    attr.setSRS(srs);
287

    
288
                    return null;
289
                }
290
            });
291
            return fType;
292
        } catch (ResourceExecuteException e) {
293
            throw new InitializeException(e);
294
                        // } finally {
295
            // this.resourcesEnd();
296
        }
297
    }
298

    
299
//        private String getSRSFromPrj(String srsParameters) {
300
//                // TODO identificar que SRS hay que usar, ya sea
301
//                // el que se recibe de los parametros o el que
302
//                // conicida con el que se ha encontrado en el
303
//                // prg... y si ninguna de las dos que?
304
//                return null;
305
//        }
306
    protected SHPStoreParameters getShpParameters() {
307
        return (SHPStoreParameters) getParameters();
308
    }
309

    
310
    public String getProviderName() {
311
        return NAME;
312
    }
313

    
314
    public boolean allowWrite() {
315
        return this.shpFile.isEditable();
316
    }
317

    
318
    /**
319
     *
320
     * @param index
321
     * @param featureType
322
     * @return
323
     * @throws ReadException
324
     */
325
    protected FeatureProvider getFeatureProviderByIndex(long index,
326
            FeatureType featureType) throws DataException {
327
                 this.open();
328
//         this.resourcesBegin();
329
        try {
330

    
331
            FeatureProvider featureProvider = super.getFeatureProviderByIndex(index,
332
                    featureType);
333
            featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
334
            return featureProvider;
335
        } catch (DataException e) {
336
            throw e;
337
        } catch (CreateEnvelopeException e) {
338
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
339
        } catch (CreateGeometryException e) {
340
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
341
        }
342

    
343
    }
344

    
345
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
346
            long index, FeatureType featureType) throws DataException {
347
                // this.open();
348
        // this.resourcesBegin();
349
        try {
350
            super.initFeatureProviderByIndex(featureProvider, index, featureType);
351
            featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
352
        } catch (CreateEnvelopeException e) {
353
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
354
        } catch (CreateGeometryException e) {
355
            throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
356
        }
357
    }
358

    
359
    /**
360
     *
361
     * @param featureProvider
362
     * @throws DataException
363
     */
364
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
365
            throws DataException {
366

    
367
        FeatureType featureType = featureProvider.getType();
368
        long index = ((Long) featureProvider.getOID()).longValue();
369
        boolean hasGeometry = false;
370
        int i = featureType.getDefaultGeometryAttributeIndex();
371
        if (i >= 0) {
372
            if (!featureProvider.isReadOnly(i)) {
373
                try {
374
                    Geometry geom = this.shpFile.getGeometry(index);
375
                    featureProvider.set(i, geom);
376
                } catch (CreateGeometryException e) {
377
                    throw new ReadException(getProviderName(), e);
378
                }
379
            }
380
            hasGeometry = true;
381
        }
382
        if (hasDBFAttributes(featureType, hasGeometry)) {
383
            super.loadFeatureProviderByIndex(featureProvider);
384
        }
385

    
386
    }
387

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

    
404
    protected void loadValue(FeatureProvider featureProvider, int rowIndex,
405
            FeatureAttributeDescriptor descriptor) throws ReadException {
406
        if (descriptor.getType() == DataTypes.GEOMETRY) {
407
            return;
408
        } else {
409
            super.loadValue(featureProvider, rowIndex, descriptor);
410
        }
411
    }
412

    
413
    public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
414
        FeatureProvider data = new SHPFeatureProvider(this, type);
415
        return data;
416
    }
417

    
418
    protected void openFile() throws IOException, DataException {
419
        super.openFile();
420
        this.shpFile.open();
421

    
422
    }
423

    
424
    protected void closeFile() throws CloseException {
425
        super.closeFile();
426
        if (!this.shpFile.isOpen()) {
427
            return;
428
        }
429
        this.shpFile.close();
430
    }
431

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

    
450
    public void performChanges(Iterator deleteds, Iterator inserteds,
451
            Iterator updateds, Iterator originalFeatureTypesUpdated)
452
            throws PerformEditingException {
453

    
454
        /*
455
         * This will throw an exception if there are new fields
456
         * with names too long
457
         */
458
        checkNewFieldsNameSize(originalFeatureTypesUpdated);
459

    
460
        final FeatureType fType;
461
        try {
462
            fType = this.getStoreServices().getDefaultFeatureType();
463
        } catch (DataException e) {
464
            throw new PerformEditingException(this.getProviderName(), e);
465
        }
466
        // TODO Comprobar el campo de geometria
467

    
468
        final EditableFeatureType dbfFtype = fType.getEditable();
469

    
470
        removeGeometryColumn(dbfFtype);
471

    
472
                // try {
473
        // this.resourcesBegin();
474
        // } catch (ResourceExecuteException e1) {
475
        // throw new PerformEditingException(this.getName(), e1);
476
        // }
477
        try {
478
            // TODO repasar el concepto de enUso de un recurso.
479
            loTengoEnUso = true;
480
            resourceCloseRequest();
481

    
482
            getResource().execute(new ResourceAction() {
483
                public Object run() throws Exception {
484
                    FeatureSet set = null;
485
                    DisposableIterator iter = null;
486
                    try {
487
                        set = getFeatureStore().getFeatureSet();
488
                        writer = new SHPFeatureWriter(getProviderName());
489

    
490
                        SHPStoreParameters shpParams = getShpParameters();
491
                        SHPStoreParameters tmpParams
492
                                = (SHPStoreParameters) shpParams.getCopy();
493

    
494
                        File tmp_base = File.createTempFile(
495
                                "tmp_" + System.currentTimeMillis(), null);
496
                        String str_base = tmp_base.getCanonicalPath();
497

    
498
                        tmpParams.setDBFFile(str_base + ".dbf");
499
                        tmpParams.setSHPFile(str_base + ".shp");
500
                        tmpParams.setSHXFile(str_base + ".shx");
501

    
502
                        writer.begin(tmpParams, fType, dbfFtype, set.getSize());
503

    
504
                        iter = set.fastIterator();
505
                        while (iter.hasNext()) {
506
                            Feature feature = (Feature) iter.next();
507
                            writer.append(feature);
508
                        }
509

    
510
                        writer.end();
511
                        loTengoEnUso = false;
512
                        close();
513

    
514

    
515
                        File tmpPrjFile = SHP.getPrjFile(tmpParams.getSHPFile());
516
                        try {
517
                        FileUtils.writeStringToFile(tmpPrjFile, tmpParams.getCRS().export(ICRSFactory.FORMAT_WKT_ESRI));
518
                        } catch(Exception e) {
519
                            logger.info("Can't write prj file '"+tmpPrjFile.getAbsolutePath()+"'.");
520
                        }
521

    
522
                        if (!shpParams.getDBFFile().delete()) {
523
                            logger.debug("Can't delete dbf file '"+shpParams.getDBFFile()+"'.");
524
                            throw new IOException("Can't delete dbf '"+FilenameUtils.getBaseName(shpParams.getDBFFileName())+"' file to replace with the new dbf.\nThe new dbf is in temporary file '"+str_base+"'");
525
                        }
526
                        if (!shpParams.getSHPFile().delete()) {
527
                            logger.debug("Can't delete dbf file '"+shpParams.getSHPFile()+"'.");
528
                            throw new IOException("Can't delete shp '"+FilenameUtils.getBaseName(shpParams.getSHPFileName())+"' file to replace with the new shp.\nThe new shp is in temporary file '"+str_base+"'");
529
                        }
530
                        if (!shpParams.getSHXFile().delete()) {
531
                            logger.debug("Can't delete dbf file '"+shpParams.getSHXFile()+"'.");
532
                            throw new IOException("Can't delete shx '"+FilenameUtils.getBaseName(shpParams.getSHXFileName())+"' file to replace with the new shx.\nThe new shx is in temporary file '"+str_base+"'");
533
                        }
534

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

    
555
                        FileUtils.moveFile(
556
                            tmpPrjFile,
557
                            SHP.getPrjFile(shpParams.getSHPFile()));
558

    
559
                        resourcesNotifyChanges();
560
                        initFeatureType();
561
                        return null;
562
                    } finally {
563
                        loTengoEnUso = false;
564
                        dispose(set);
565
                        dispose(iter);
566
                    }
567
                }
568
            });
569

    
570
        } catch (Exception e) {
571
            throw new PerformEditingException(this.getProviderName(), e);
572
        }
573

    
574
    }
575

    
576

    
577
    protected void resourceCloseRequest() throws ResourceException {
578
                // super.resourceCloseRequest();
579
        // this.shpResource.closeRequest();
580
        // this.shxResource.closeRequest();
581
        getResource().closeRequest();
582
    }
583

    
584
    public Envelope getEnvelope() throws DataException {
585
        this.open();
586
        return (Envelope) this.getDynValue("Envelope");
587
    }
588

    
589
    public void append(final FeatureProvider featureProvider) throws DataException {
590
//                this.resourcesBegin();
591
//                try {
592

    
593
        getResource().execute(new ResourceAction() {
594
            public Object run() throws Exception {
595
                writer.append(getStoreServices().createFeature(featureProvider));
596
                return null;
597
            }
598
        });
599
//                } finally {
600
//                        this.resourcesEnd();
601
//                }
602

    
603
    }
604

    
605
    public void beginAppend() throws DataException {
606
                // this.resourcesBegin();
607
        // try {
608

    
609
        getResource().execute(new ResourceAction() {
610
            public Object run() throws Exception {
611
                FeatureStore store = getFeatureStore();
612
                FeatureType fType = store.getDefaultFeatureType();
613

    
614
                                // TODO Comprobar el campo de geometria
615
                EditableFeatureType dbfFtype = fType.getEditable();
616

    
617
                removeGeometryColumn(dbfFtype);
618
                FeatureSet set = store.getFeatureSet();
619

    
620
                writer = new SHPFeatureWriter(getProviderName());
621

    
622
                writer.begin(getShpParameters(), fType, dbfFtype, set.getSize());
623
                return null;
624
            }
625
        });
626
                // } finally {
627
        // this.resourcesEnd();
628
        // }
629

    
630
    }
631

    
632
    public void endAppend() throws DataException {
633
//                this.resourcesBegin();
634
//                try {
635
        getResource().execute(new ResourceAction() {
636
            public Object run() throws Exception {
637
                writer.end();
638
                close();
639

    
640
                SHPStoreParameters shpParameters = SHPStoreProvider.this.getShpParameters();
641
                File prjFile = SHP.getPrjFile(shpParameters.getFile());
642
                try {
643
                FileUtils.writeStringToFile(prjFile, shpParameters.getCRS().export(ICRSFactory.FORMAT_WKT_ESRI));
644
                } catch(Exception e) {
645
                    logger.info("Can't write prj file '"+prjFile.getAbsolutePath()+"'.");
646
                }
647

    
648
                resourcesNotifyChanges();
649
                return null;
650
            }
651
        });
652
//                } finally {
653
//                        this.resourcesEnd();
654
//                }
655

    
656
    }
657

    
658
    public Object getSourceId() {
659
        return this.getShpParameters().getFile();
660
    }
661
}