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

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

    
79
/**
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(SHPStoreProvider.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
    /**
101
     * @param params
102
     * @param storeServices
103
     * @throws InitializeException
104
     */
105
    public SHPStoreProvider(SHPStoreParameters params, DataStoreProviderServices storeServices)
106
        throws InitializeException {
107
        super(params, storeServices, FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME));
108
    }
109

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

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

    
117
    @Override
118
    public SHPStoreParameters getParameters() {
119
        return (SHPStoreParameters) super.getParameters();
120
    }
121

    
122
    @Override
123
    public Object getDynValue(String name) throws DynFieldNotFoundException {
124
        if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
125

    
126
            return this.getShpParameters().getCRS();
127

    
128
        } else if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
129
            try {
130
                return this.shpFile.getFullExtent();
131
            } catch (ReadException e) {
132
                return null;
133
            }
134
        }
135
        return super.getDynValue(name);
136
    }
137

    
138
    protected void initResource(DBFStoreParameters params, DataStoreProviderServices storeServices)
139
        throws InitializeException {
140

    
141
        SHPStoreParameters shpParams = (SHPStoreParameters) params;
142
        resource = (MultiResource) createResource(MultiResource.TYPE_NAME, new Object[] { shpParams.getSHPFileName() });
143

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

    
148
        resource.frozen();
149
        resource.addMultiResourceConsumer(this);
150
        super.initResource(resource, storeServices);
151
    }
152

    
153
    ;
154

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

    
159
    /**
160
     *
161
     * @throws ResourceNotifyChangesException
162
     */
163
    protected void resourcesNotifyChanges() throws ResourceNotifyChangesException {
164
        getResource().notifyChanges();
165
        // TODO .prj
166

    
167
    }
168

    
169
    /**
170
     * @throws ResourceNotifyCloseException
171
     *
172
     */
173
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
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
        getResource().notifyOpen();
197
    }
198

    
199
    protected static EditableFeatureAttributeDescriptor addGeometryColumn(EditableFeatureType fType) {
200

    
201
        EditableFeatureAttributeDescriptor attrTmp = null;
202
        EditableFeatureAttributeDescriptor attr = null;
203
        Iterator<?> iter = fType.iterator();
204
        while (iter.hasNext()) {
205
            attrTmp = (EditableFeatureAttributeDescriptor) iter.next();
206
            if (attrTmp.getType() == DataTypes.GEOMETRY) {
207
                if (attr != null) {
208
                    // Two geom fields not allowed
209
                    fType.remove(attrTmp.getName());
210
                } else {
211
                    attr = attrTmp;
212
                }
213
            }
214
        }
215

    
216
        if (attr == null) {
217
            String geofield = createGeometryFieldName(fType);
218
            attr = fType.add(geofield, DataTypes.GEOMETRY);
219
            attr.setDefaultValue(null);
220
        }
221

    
222
        attr.setObjectClass(Geometry.class);
223
        attr.setAllowNull(true);
224
        fType.setDefaultGeometryAttributeName(attr.getName());
225
        return attr;
226

    
227
    }
228

    
229
    private static String createGeometryFieldName(FeatureType ft) {
230

    
231
        if (ft.getAttributeDescriptor(GEOMETRY_ATTIBUTE_NAME) == null) {
232
            return GEOMETRY_ATTIBUTE_NAME;
233
        }
234

    
235
        int i = 0;
236
        String candidate = GEOMETRY_ATTIBUTE_NAME + i;
237
        while (ft.getAttributeDescriptor(candidate) != null) {
238
            i++;
239
            candidate = GEOMETRY_ATTIBUTE_NAME + i;
240
        }
241
        return candidate;
242
    }
243

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

    
257
    protected EditableFeatureType getTheFeatureType() throws InitializeException, OpenException {
258
        final EditableFeatureType fType = super.getTheFeatureType();
259
        this.open();
260
        try {
261
            getResource().execute(new ResourceAction() {
262

    
263
                public Object run() throws Exception {
264
                    EditableFeatureAttributeDescriptor attr = addGeometryColumn(fType);
265

    
266
                    attr.setGeometryType(geomManager.getGeometryType(
267
                        shpFile.getGeometryType(),
268
                        shpFile.getGeometrySubType()
269
                    ));
270

    
271
                    IProjection srs = getShpParameters().getCRS();
272
                    attr.setSRS(srs);
273

    
274
                    return null;
275
                }
276
            });
277
            return fType;
278
        } catch (ResourceExecuteException e) {
279
            throw new InitializeException(e);
280
        }
281
    }
282

    
283
    protected SHPStoreParameters getShpParameters() {
284
        return (SHPStoreParameters) getParameters();
285
    }
286

    
287
    public String getProviderName() {
288
        return NAME;
289
    }
290

    
291
    public boolean allowWrite() {
292
        return this.shpFile.isEditable() &&
293
            super.allowWrite() &&
294
            !this.getShpParameters().getLoadCorruptGeometriesAsNull() &&
295
            !this.getShpParameters().getAllowInconsistenciesInGeometryType() &&
296
            !this.getShpParameters().getFixLinearRings();
297
    }
298

    
299
    /**
300
     *
301
     * @param index
302
     * @param featureType
303
     * @return
304
     * @throws ReadException
305
     */
306
    protected FeatureProvider getFeatureProviderByIndex(long index, FeatureType featureType) throws DataException {
307
        this.open();
308
        try {
309

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

    
321
    }
322

    
323
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider, long index, FeatureType featureType)
324
        throws DataException {
325
        try {
326
            super.initFeatureProviderByIndex(featureProvider, index, featureType);
327
            featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
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
     *
337
     * @param featureProvider
338
     * @throws DataException
339
     */
340
    @Override
341
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider) throws DataException {
342

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

    
367
    }
368

    
369
    public class ReadGeometryException extends ReadException {
370

    
371
        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.";
372
        private final static String MESSAGE_KEY = "_ReadGeometryException";
373
        private static final long serialVersionUID = 2626155328734197112L;
374

    
375
        public ReadGeometryException(String store, Object oid, Throwable cause) {
376
            super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
377
            setValue("store", store);
378
            setValue("storeParameters",getParameters());
379
        }
380
    }
381

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

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

    
405
    public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
406
        FeatureProvider data = new SHPFeatureProvider(this, type);
407
        return data;
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) throws DataException {
425
        this.open();
426
        return ((Boolean) getResource().execute(new ResourceAction() {
427

    
428
            public Object run() throws Exception {
429
                boolean value = shpFile.canWriteGeometry(geometryType);
430
                return value ? Boolean.TRUE : Boolean.FALSE;
431
            }
432
        })).booleanValue();
433
    }
434

    
435
    @SuppressWarnings("rawtypes")
436
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds,
437
        Iterator originalFeatureTypesUpdated) throws PerformEditingException {
438

    
439
        /*
440
         * This will throw an exception if there are new fields
441
         * with names too long
442
         */
443
        checkNewFieldsNameSize(originalFeatureTypesUpdated);
444

    
445
        final FeatureType fType;
446
        try {
447
            fType = this.getStoreServices().getDefaultFeatureType();
448
        } catch (DataException e) {
449
            throw new PerformEditingException(this.getProviderName(), e);
450
        }
451
        // TODO Comprobar el campo de geometria
452

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

    
455
        removeGeometryColumn(dbfFtype);
456

    
457
        try {
458
            // TODO repasar el concepto de enUso de un recurso.
459
            loTengoEnUso = true;
460
            resourceCloseRequest();
461

    
462
            getResource().execute(new ResourceAction() {
463

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

    
471
                        SHPStoreParameters shpParams = getShpParameters();
472
                        SHPStoreParameters tmpParams = (SHPStoreParameters) shpParams.getCopy();
473

    
474
                        File tmp_base = File.createTempFile("tmp_" + System.currentTimeMillis(), null);
475
                        String str_base = tmp_base.getCanonicalPath();
476

    
477
                        tmpParams.setDBFFile(str_base + ".dbf");
478
                        tmpParams.setSHPFile(str_base + ".shp");
479
                        tmpParams.setSHXFile(str_base + ".shx");
480

    
481
                        writer.begin(tmpParams, fType, dbfFtype, set.getSize());
482

    
483
                        iter = set.fastIterator();
484
                        while (iter.hasNext()) {
485
                            Feature feature = (Feature) iter.next();
486
                            writer.append(feature);
487
                        }
488

    
489
                        writer.end();
490
                        loTengoEnUso = false;
491
                        close();
492

    
493

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

    
523
                        File prjFile = SHP.getPrjFile(shpParams.getSHPFile());
524
                        if (prjFile.exists()) {
525
                            if (!prjFile.delete()) {
526
                                logger.debug("Can't delete prj file '" + prjFile + "'.");
527
                                throw new IOException("Can't delete shx '"
528
                                    + FilenameUtils.getBaseName(prjFile.getPath())
529
                                    + "' file to replace with the new shx.\nThe new shx is in temporary file '"
530
                                    + str_base + "'");
531
                            }
532
                        }
533
                        FileUtils.moveFile(tmpParams.getDBFFile(), shpParams.getDBFFile());
534
                        FileUtils.moveFile(tmpParams.getSHPFile(), shpParams.getSHPFile());
535
                        FileUtils.moveFile(tmpParams.getSHXFile(), shpParams.getSHXFile());
536
                        FileUtils.moveFile(tmpParams.getCPGFile(), shpParams.getCPGFile());
537

    
538
                        savePrjFile(shpParams.getFile(), tmpParams.getCRS());
539

    
540
                        resourcesNotifyChanges();
541
                        initFeatureType();
542
                        return null;
543
                    } finally {
544
                        loTengoEnUso = false;
545
                        dispose(set);
546
                        dispose(iter);
547
                    }
548
                }
549
            });
550

    
551
        } catch (Exception e) {
552
            throw new PerformEditingException(this.getProviderName(), e);
553
        }
554

    
555
    }
556

    
557
    protected void resourceCloseRequest() throws ResourceException {
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
        getResource().execute(new ResourceAction() {
568

    
569
            public Object run() throws Exception {
570
                writer.append(getStoreServices().createFeature(featureProvider));
571
                return null;
572
            }
573
        });
574
    }
575

    
576
    public void beginAppend() throws DataException {
577
        getResource().execute(new ResourceAction() {
578

    
579
            public Object run() throws Exception {
580
                FeatureStore store = getFeatureStore();
581
                FeatureType fType = store.getDefaultFeatureType();
582

    
583
                // TODO Comprobar el campo de geometria
584
                EditableFeatureType dbfFtype = fType.getEditable();
585

    
586
                removeGeometryColumn(dbfFtype);
587
                FeatureSet set = store.getFeatureSet();
588

    
589
                writer = new SHPFeatureWriter(getProviderName());
590

    
591
                writer.begin(getShpParameters(), fType, dbfFtype, set.getSize());
592
                return null;
593
            }
594
        });
595
    }
596

    
597
    public void endAppend() throws DataException {
598
        getResource().execute(new ResourceAction() {
599

    
600
            public Object run() throws Exception {
601
                writer.end();
602
                close();
603

    
604
                SHPStoreParameters shpParameters = SHPStoreProvider.this.getShpParameters();
605

    
606
                savePrjFile(shpParameters.getFile(), shpParameters.getCRS());
607

    
608
                resourcesNotifyChanges();
609
                return null;
610
            }
611
        });
612
    }
613

    
614
    public Object getSourceId() {
615
        return this.getShpParameters().getFile();
616
    }
617

    
618

    
619
}