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.dbf / src / main / java / org / gvsig / fmap / dal / store / dbf / DBFStoreProvider.java @ 45387

History | View | Annotate | Download (27.9 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.dbf;
24

    
25
import java.io.File;
26
import java.io.IOException;
27
import java.math.BigDecimal;
28
import java.nio.charset.Charset;
29
import java.util.ArrayList;
30
import java.util.Iterator;
31
import java.util.List;
32
import java.util.logging.Level;
33

    
34
import org.apache.commons.io.FileUtils;
35
import org.apache.commons.lang3.StringUtils;
36

    
37
import org.gvsig.fmap.dal.DALLocator;
38
import org.gvsig.fmap.dal.DataManager;
39
import org.gvsig.fmap.dal.DataServerExplorer;
40
import org.gvsig.fmap.dal.DataStore;
41
import org.gvsig.fmap.dal.DataStoreNotification;
42
import org.gvsig.fmap.dal.DataTypes;
43
import org.gvsig.fmap.dal.FileHelper;
44
import org.gvsig.fmap.dal.exception.CloseException;
45
import org.gvsig.fmap.dal.exception.DataException;
46
import org.gvsig.fmap.dal.exception.FileNotFoundException;
47
import org.gvsig.fmap.dal.exception.InitializeException;
48
import org.gvsig.fmap.dal.exception.OpenException;
49
import org.gvsig.fmap.dal.exception.ReadException;
50
import org.gvsig.fmap.dal.exception.UnsupportedVersionException;
51
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
52
import org.gvsig.fmap.dal.feature.EditableFeatureType;
53
import org.gvsig.fmap.dal.feature.Feature;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
55
import org.gvsig.fmap.dal.feature.FeatureQuery;
56
import org.gvsig.fmap.dal.feature.FeatureSet;
57
import org.gvsig.fmap.dal.feature.FeatureStore;
58
import org.gvsig.fmap.dal.feature.FeatureType;
59
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
60
import org.gvsig.fmap.dal.feature.exception.AttributeNameException;
61
import org.gvsig.fmap.dal.feature.exception.AttributeNameTooLongException;
62
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
63
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
64
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
65
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
66
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
67
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
68
import org.gvsig.fmap.dal.resource.ResourceAction;
69
import org.gvsig.fmap.dal.resource.exception.ResourceException;
70
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
71
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
72
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
73
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
74
import org.gvsig.fmap.dal.resource.file.FileResource;
75
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
76
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
77
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
78
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
79
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
80
import org.gvsig.fmap.dal.store.dbf.utils.DbaseFile;
81
import org.gvsig.fmap.dal.store.dbf.utils.FieldFormatter;
82
import org.gvsig.metadata.MetadataLocator;
83
import org.gvsig.metadata.MetadataManager;
84
import org.gvsig.metadata.exceptions.MetadataException;
85
import org.gvsig.tools.dataTypes.CoercionException;
86
import org.gvsig.tools.dispose.DisposableIterator;
87
import org.gvsig.tools.dynobject.DynObject;
88
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
89
import org.gvsig.tools.exception.BaseException;
90
import org.gvsig.tools.logger.FilteredLogger;
91

    
92
import org.slf4j.Logger;
93
import org.slf4j.LoggerFactory;
94

    
95
public class DBFStoreProvider extends AbstractFeatureStoreProvider implements
96
        ResourceConsumer {
97

    
98
    private static final Logger LOG = LoggerFactory.getLogger(DBFStoreProvider.class);
99

    
100
    public static final int MAX_FIELD_NAME_LENGTH = DbaseFile.MAX_FIELD_NAME_LENGTH;
101

    
102
    public static final String NAME = DataStore.DBASE_PROVIDER_NAME;
103
    public static final String DESCRIPTION = "DBF file";
104

    
105
    public static final String METADATA_DEFINITION_NAME = NAME;
106
    private static final String METADATA_ENCODING = "Encoding";
107
    private static final String METADATA_CODEPAGE = "CodePage";
108

    
109
    private DbaseFile dbfFile = null;
110
    private ResourceProvider dbfResource;
111
    private long counterNewsOIDs = -1;
112
    private DBFFeatureWriter writer;
113

    
114
    private boolean loTengoEnUso;
115

    
116
    private boolean allowDuplicatedFieldNames;
117
    private FilteredLogger logger;
118
    
119
    protected FeatureType featureType;
120

    
121

    
122
    protected static void registerMetadataDefinition() throws MetadataException {
123
        MetadataManager manager = MetadataLocator.getMetadataManager();
124
        if (manager.getDefinition(METADATA_DEFINITION_NAME) == null) {
125
            manager.addDefinition(
126
                    METADATA_DEFINITION_NAME,
127
                    DBFStoreParameters.class.getResourceAsStream("DBFStoreMetadata.xml"),
128
                    DBFStoreParameters.class.getClassLoader()
129
            );
130
        }
131
    }
132

    
133
    public DBFStoreProvider(DBFStoreParameters params,
134
            DataStoreProviderServices storeServices)
135
            throws InitializeException {
136
        this(
137
                params,
138
                storeServices,
139
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
140
        );
141
    }
142

    
143
    protected DBFStoreProvider(DBFStoreParameters params,
144
            DataStoreProviderServices storeServices, DynObject metadata)
145
            throws InitializeException {
146
        super(params, storeServices, metadata);
147
        this.logger = new FilteredLogger(LOG, "DBFStoreProvider", -1);
148
        this.logger.setInterval(2000);
149
        this.init(params, storeServices);
150
    }
151

    
152
    protected void init(DBFStoreParameters params,
153
            DataStoreProviderServices storeServices) throws InitializeException {
154
        if (params == null) {
155
            throw new InitializeException(new NullPointerException("params is null"));
156
        }
157
        File theFile = getDBFParameters().getDBFFile();
158
        if (theFile == null) {
159
            throw new InitializeException(new NullPointerException("dbf file is null"));
160
        }
161
        initResource(params, storeServices);
162

    
163
        Charset charset = params.getEncoding();
164
        allowDuplicatedFieldNames = params.allowDuplicatedFieldNames();
165
        this.dbfFile = new DbaseFile(theFile, charset, allowDuplicatedFieldNames);
166

    
167
        writer = new DBFFeatureWriter(this.getProviderName());
168

    
169
        this.initFeatureType();
170

    
171
    }
172

    
173
    public Object getDynValue(String name) throws DynFieldNotFoundException {
174
        try {
175
            this.open();
176
        } catch (OpenException e) {
177
            throw new RuntimeException(e);
178
        }
179

    
180
        if (METADATA_ENCODING.equalsIgnoreCase(name)) {
181
            return this.dbfFile.getOriginalCharset();
182
        } else if (METADATA_CODEPAGE.equalsIgnoreCase(name)) {
183
            return this.dbfFile.getCodePageInt();
184
        }
185
        return super.getDynValue(name);
186
    }
187

    
188
    protected void initResource(DBFStoreParameters params,
189
            DataStoreProviderServices storeServices) throws InitializeException {
190

    
191
        File theFile = getDBFParameters().getDBFFile();
192
        dbfResource
193
                = this.createResource(FileResource.NAME,
194
                        new Object[]{theFile.getAbsolutePath()});
195
        dbfResource.addConsumer(this);
196
    }
197

    
198
    protected void initResource(ResourceProvider resource,
199
        DataStoreProviderServices storeServices){
200
        dbfResource = resource;
201
        dbfResource.addConsumer(this);
202
    }
203

    
204
    public String getProviderName() {
205
        return NAME;
206
    }
207

    
208
    protected DBFStoreParameters getDBFParameters() {
209
        return (DBFStoreParameters) super.getParameters();
210
    }
211

    
212
    public DataServerExplorer getExplorer() throws ReadException {
213
        DataManager manager = DALLocator.getDataManager();
214
        FilesystemServerExplorerParameters params;
215
        try {
216
            params = (FilesystemServerExplorerParameters) manager
217
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
218
            params.setRoot(this.getDBFParameters().getDBFFile().getParent());
219
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
220
        } catch (DataException | ValidateDataParametersException e) {
221
            throw new ReadException(this.getName(), e);
222
        }
223
    }
224

    
225
    protected FeatureProvider internalGetFeatureProviderByReference(
226
            FeatureReferenceProviderServices reference, FeatureType featureType)
227
            throws DataException {
228
        return this.getFeatureProviderByIndex(
229
                ((Number) reference.getOID()).longValue(), featureType);
230
    }
231

    
232
    public void performChanges(Iterator deleteds, Iterator inserteds,
233
            Iterator updateds, Iterator originalFeatureTypesUpdated)
234
            throws PerformEditingException {
235

    
236
        /*
237
         * This will throw an exception if there are new fields
238
         * with names too long
239
         */
240
        checkNewFieldsNameSize(originalFeatureTypesUpdated);
241

    
242
        try {
243
            // TODO repasar el concepto de enUso de un recurso.
244
            loTengoEnUso = true;
245
            final FeatureStore theStore = this.getStoreServices().getFeatureStore();
246
            resourceCloseRequest();
247
            getResource().execute(new ResourceAction() {
248

    
249
                public Object run() throws Exception {
250
                    FeatureSet set = null;
251
                    DisposableIterator iter = null;
252
                    try {
253
                        set = theStore.getFeatureSet();
254
                        DBFStoreParameters tmpParams
255
                                = (DBFStoreParameters) getDBFParameters().getCopy();
256

    
257
                        File tmp_file = File.createTempFile(
258
                                "tmp_" + System.currentTimeMillis(), ".dbf");
259
                        tmp_file.deleteOnExit();
260

    
261
                        tmpParams.setDBFFile(tmp_file);
262

    
263
                        writer.begin(tmpParams, theStore.getDefaultFeatureType(),
264
                                set.getSize());
265

    
266
                        iter = set.fastIterator();
267
                        while (iter.hasNext()) {
268
                            Feature feature = (Feature) iter.next();
269
                            writer.append(feature);
270
                        }
271

    
272
                        writer.end();
273
                        loTengoEnUso = false;
274
                        try {
275
                            close();
276
                        } catch (CloseException e1) {
277
                            throw new PerformEditingException(getProviderName(), e1);
278
                        }
279
                        getDBFParameters().getDBFFile().delete();
280

    
281
                        File target_file = getDBFParameters().getDBFFile();
282
                        if (target_file.exists()) {
283
                            target_file.delete();
284
                        }
285
                        tmp_file.renameTo(target_file);
286

    
287
                        if (tmp_file.exists() && !target_file.exists()) {
288
                            // Renaming failed, let's simply copy.
289
                            // We assume we cannot delete it, but we
290
                            // used deleteOnExit and it's
291
                            // temporary, so no problem
292
                            LOG.info("Warning: copying tmp file instead of renaming: "
293
                                    + target_file.getName());
294
                            FileUtils.copyFile(tmp_file, target_file);
295
                        }
296

    
297
                        resourcesNotifyChanges();
298
                        initFeatureType();
299
                    } finally {
300
                        loTengoEnUso = false;
301
                        if (set != null) {
302
                            set.dispose();
303
                        }
304
                        if (iter != null) {
305
                            iter.dispose();
306
                        }
307
                    }
308
                    return null;
309
                }
310
            });
311
        } catch (ResourceExecuteException | ResourceException e) {
312
            throw new PerformEditingException(NAME, e);
313
        }
314

    
315
        this.counterNewsOIDs = -1;
316
    }
317

    
318
    protected void checkNewFieldsNameSize(Iterator ft_upd) throws PerformEditingException {
319

    
320
        String long_fields = getNewFieldsWithNameTooLong(ft_upd);
321
        if (long_fields != null) {
322
            AttributeNameException ane = new AttributeNameTooLongException(
323
                    long_fields,
324
                    getProviderName(),
325
                    MAX_FIELD_NAME_LENGTH);
326
            throw new PerformEditingException(getProviderName(), ane);
327
        }
328
    }
329

    
330
    /**
331
     * Returns null or a string which is a comma-separated list
332
     *
333
     * @param ft_updated
334
     * @return
335
     */
336
    protected String getNewFieldsWithNameTooLong(Iterator ft_updated) {
337

    
338
        String resp = "";
339
        FeatureTypeChanged item;
340
        FeatureType ft;
341
        FeatureAttributeDescriptor[] atts;
342
        while (ft_updated.hasNext()) {
343
            item = (FeatureTypeChanged) ft_updated.next();
344
            ft = item.getTarget();
345
            atts = ft.getAttributeDescriptors();
346
            for (FeatureAttributeDescriptor att : atts) {
347
                if (att.getName().length() > MAX_FIELD_NAME_LENGTH) {
348
                    if (resp.length() == 0) {
349
                        resp = att.getName();
350
                    } else {
351
                        resp = resp + ", " + att.getName();
352
                    }
353
                }
354
            }
355
        }
356

    
357
        if (resp.length() == 0) {
358
            return null;
359
        } else {
360
            return "(" + resp + ")";
361
        }
362
    }
363

    
364
    public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
365
        return new DBFFeatureProvider(this, type);
366
    }
367

    
368
    protected void initFeatureType() throws InitializeException {
369
        FeatureType defaultType = this.getTheFeatureType().getNotEditableCopy();
370
        this.setFeatureType(defaultType);
371
    }
372

    
373
    private void setFeatureType(FeatureType ftype) {
374
        FeatureStoreProviderServices store = this.getStoreServices();
375
        List<FeatureType> ftypes = new ArrayList<>();
376
        ftypes.add(ftype);
377
        this.featureType = ftype;
378
        store.setFeatureTypes(ftypes, ftype);
379
    }
380
        
381
    protected EditableFeatureType getTheFeatureType() throws InitializeException {
382
        try {
383
            this.open();
384
        } catch (DataException e) {
385
            throw new InitializeException(this.getProviderName(), e);
386
        }
387
        EditableFeatureType featureType = (EditableFeatureType) getResource().execute(
388
            new ResourceAction() {
389
                public Object run() throws Exception {
390
                    EditableFeatureType featureType = getStoreServices().createFeatureType(getName());
391
                    featureType.setHasOID(true);
392
                    dbfFile.getHeader().toFeatureType(
393
                            featureType,
394
                            getDBFParameters().handleDatesAsStrings()
395
                    );
396
                    return featureType;
397
                }
398
            }
399
        );
400
        return featureType;
401
    }
402
    
403
    
404
    protected void loadValue(FeatureProvider featureProvider, long rowIndex,
405
            FeatureAttributeDescriptor descriptor) throws ReadException {
406

    
407
        if (descriptor.getEvaluator() != null) {
408
            // Nothing to do
409
            return;
410
        }
411

    
412
        int dbfFieldIndex = this.dbfFile.getFieldIndex(descriptor.getName());
413

    
414
        if (dbfFieldIndex < 0) {
415
            // Someone asked to load a field
416
            // which does not exist in the DBF file. This can happen
417
            // in editing process when a field has been added
418
            // in the current editing session, so we simply do nothing.
419
            // The expansion manager is expected to manage those new fields
420
            // and their values.
421
            this.logger.warn("The requested field ("+descriptor.getName()+") does not exist in the DBF file. Assumed it's a new field in editing mode.");
422
            return;
423
        }
424

    
425
        String value = null;
426
        try {
427
            value = this.dbfFile.getStringFieldValue(rowIndex, dbfFieldIndex);
428
        } catch (DataException e) {
429
            throw new ReadException(this.getName(), e);
430
        }
431
        value = value.trim();
432
        FieldFormatter formatter = new FieldFormatter();
433
        
434
        int index = descriptor.getIndex();
435
        Object defaultValue = descriptor.getDefaultValueCoerced();
436
        
437
        switch (descriptor.getType()) {
438
            case DataTypes.STRING:
439
                featureProvider.set(index, formatter.parseString(value, (String) defaultValue));
440
                break;
441

    
442
            case DataTypes.DECIMAL:
443
                featureProvider.set(index, 
444
                    formatter.parseDecimal(
445
                        value, 
446
                        descriptor.getMathContext(), 
447
                        descriptor.getScale(),
448
                        (BigDecimal) defaultValue
449
                  )
450
                );
451
                break;
452

    
453
            case DataTypes.DOUBLE:
454
                featureProvider.set(index, formatter.parseDouble(value, (Double) defaultValue));
455
                break;
456

    
457
            case DataTypes.FLOAT:
458
                featureProvider.set(index, formatter.parseFloat(value, (Float) defaultValue));
459
                break;
460

    
461
            case DataTypes.LONG:
462
                featureProvider.set(index, formatter.parseLong(value, (Long) defaultValue));
463
                break;
464

    
465
            case DataTypes.INT:
466
                featureProvider.set(index, formatter.parseInt(value, (Integer) defaultValue));
467
                break;
468

    
469
            case DataTypes.BYTE:
470
                featureProvider.set(index, formatter.parseByte(value, (Byte) defaultValue));
471
                break;
472

    
473
            case DataTypes.BOOLEAN:
474
                featureProvider.set(index, formatter.parseBoolean(value, (Boolean) defaultValue));
475
                break;
476

    
477
            case DataTypes.TIMESTAMP:
478
                featureProvider.set(index, formatter.parseTimestamp(value, (java.sql.Timestamp) defaultValue));
479
                break;
480
                
481
            case DataTypes.TIME:
482
                featureProvider.set(index, formatter.parseTime(value, (java.sql.Time) defaultValue));
483
                break;
484

    
485
            case DataTypes.DATE:
486
                featureProvider.set(index, formatter.parseDate(value, (java.sql.Date) defaultValue));
487
                break;
488

    
489
            default: {
490
                    Object v;
491
                    try {
492
                        v = descriptor.getDataType().coerce(value);
493
                    } catch (CoercionException ex) {
494
                        v = defaultValue;
495
                    }
496
                    featureProvider.set(index, v);
497
                }
498
                break;
499
        }
500
    }
501

    
502
    protected FeatureProvider getFeatureProviderByIndex(long index) throws DataException {
503
        return this
504
                .getFeatureProviderByIndex(index, this.getStoreServices()
505
                        .getDefaultFeatureType());
506
    }
507

    
508
    public long getFeatureCount() throws ReadException, OpenException,
509
            ResourceNotifyChangesException {
510
        this.open();
511
        return (long) getResource().execute(new ResourceAction() {
512
            public Object run() throws Exception {
513
                return (long) dbfFile.getRecordCount();
514
            }
515
        });
516
    }
517

    
518
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
519
            throws DataException {
520
        return new DBFSetProvider(this, query, featureType);
521
    }
522

    
523
    public boolean canCreate() {
524
        return true;
525
    }
526

    
527
    public boolean canWriteGeometry(int geometryType, int geometrySubType) throws DataException {
528
        return false;
529
    }
530

    
531
    public void open() throws OpenException {
532
        if (this.dbfFile.isOpen()) {
533
            return;
534
        }
535
        try {
536
            getResource().execute(new ResourceAction() {
537
                public Object run() throws Exception {
538
                    openFile();
539
                    resourcesOpen();
540
                    return null;
541
                }
542
            });
543

    
544
        } catch (ResourceExecuteException e) {
545
            throw new OpenException(this.getProviderName(), e);
546
        }
547
    }
548

    
549
    protected void openFile() throws FileNotFoundException,
550
            UnsupportedVersionException, IOException, DataException {
551
        this.dbfFile.open();
552
        // necessary when editing the file
553
        this.getDBFParameters().setEffectiveEncoding(this.dbfFile.getCharsetName());
554
    }
555

    
556
    public void close() throws CloseException {
557
        if( loTengoEnUso ) {
558
            return;
559
        }
560
        if (dbfFile == null || !this.dbfFile.isOpen()) {
561
            return;
562
        }
563
        super.close();
564

    
565
        //Cerrar recurso
566
        try {
567
            getResource().execute(new ResourceAction() {
568
                public Object run() throws Exception {
569
                    closeFile();
570
                    resourcesNotifyClose();
571
                    return null;
572
                }
573
            });
574
        } catch (ResourceExecuteException  e) {
575
            throw new CloseException(this.getProviderName(), e);
576
        }
577
    }
578

    
579
    protected void closeFile() throws CloseException {
580
        this.dbfFile.close();
581
    }
582

    
583
    @Override
584
    protected void doDispose() throws BaseException {
585
        this.close();
586
        dbfFile = null;
587
        disposeResource();
588
        super.doDispose();
589
    }
590

    
591
    protected void disposeResource() {
592
        this.dbfResource.removeConsumer(this);
593
        dbfResource = null;
594
    }
595

    
596
    public boolean closeResourceRequested(ResourceProvider resource) {
597
        try {
598
            this.close();
599
        } catch (CloseException e) {
600
            return false;
601
        }
602
        return true;
603
    }
604

    
605
    public boolean allowWrite() {
606
        if(allowDuplicatedFieldNames){
607
            return false;
608
        }
609
        return this.dbfFile.isWritable();
610
    }
611

    
612
    public void refresh() throws OpenException {
613
        try {
614
            this.close();
615
        } catch (CloseException e) {
616
            throw new OpenException(this.getProviderName(), e);
617
        }
618
        this.open();
619
        try {
620
            this.initFeatureType();
621
        } catch (InitializeException e) {
622
            throw new OpenException(this.getProviderName(), e);
623
        }
624
    }
625

    
626
    /**
627
     *
628
     * @param index
629
     * @param featureType
630
     * @return
631
     * @throws ReadException
632
     */
633
    protected FeatureProvider getFeatureProviderByIndex(long index,
634
            FeatureType featureType) throws DataException {
635
        FeatureProvider featureProvider = this.createFeatureProvider(featureType);
636
        featureProvider.setOID(index);
637
        return featureProvider;
638
    }
639

    
640
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
641
            long index, FeatureType featureType) throws DataException {
642
        featureProvider.setOID(index);
643
    }
644

    
645
    /**
646
     *
647
     * @param featureProvider
648
     * @throws DataException
649
     */
650
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
651
            throws DataException {
652

    
653
        long index = ((Long) featureProvider.getOID());
654
        int rec_count = this.dbfFile.getRecordCount();
655

    
656
        if (index >= rec_count) {
657

    
658
            ReadException rex = new ReadException(this.getName(),
659
                    new ArrayIndexOutOfBoundsException(
660
                            "Index of requested feature ("
661
                            + index + ") is >= record count (" + rec_count + ")"));
662

    
663
            LOG.info("Error while loading feature. ", rex);
664
            throw rex;
665
        }
666

    
667
        for (FeatureAttributeDescriptor desc : featureProvider.getType()) {
668
            this.loadValue(featureProvider, index, desc);
669
        }
670
    }
671

    
672
    public int getOIDType() {
673
        return DataTypes.LONG;
674
    }
675

    
676
    public Object createNewOID() {
677
        if (this.counterNewsOIDs < 0) {
678
            try {
679
                this.counterNewsOIDs = this.getFeatureCount();
680
            } catch (DataException e) {
681
                LOG.warn("Can't initialice counter for news OIDs.",e);
682
            }
683

    
684
        } else {
685
            this.counterNewsOIDs++;
686
        }
687
        return counterNewsOIDs;
688
    }
689

    
690
    public boolean supportsAppendMode() {
691
        return true;
692
    }
693

    
694
    public void append(final FeatureProvider featureProvider)
695
            throws DataException {
696
        getResource().execute(new ResourceAction() {
697
            public Object run() throws Exception {
698
                writer.append(getStoreServices().createFeature(featureProvider));
699
                return null;
700
            }
701
        });
702
    }
703

    
704
    public void beginAppend() throws DataException {
705
        this.close();
706
        getResource().execute(new ResourceAction() {
707
            public Object run() throws Exception {
708
                writer.begin(getDBFParameters(),
709
                        getStoreServices().getDefaultFeatureType(),
710
                        getStoreServices().getFeatureStore().getFeatureCount());
711
                return null;
712
            }
713
        });
714
    }
715

    
716
    public void endAppend() throws DataException {
717
        getResource().execute(new ResourceAction() {
718
            public Object run() throws Exception {
719
                writer.end();
720
                resourcesNotifyChanges();
721
                counterNewsOIDs = -1;
722
                return null;
723
            }
724
        });
725
    }
726

    
727
    public void resourceChanged(ResourceProvider resource) {
728
        if (this.getStoreServices()!=null){
729
            this.getStoreServices().notifyChange(
730
                    DataStoreNotification.RESOURCE_CHANGED,
731
                    resource);
732
        }
733
    }
734

    
735
    /**
736
     *
737
     * @throws ResourceNotifyChangesException
738
     */
739
    protected void resourcesNotifyChanges()
740
            throws ResourceNotifyChangesException {
741
        this.dbfResource.notifyChanges();
742
    }
743

    
744
    /**
745
     * @throws ResourceNotifyCloseException
746
     *
747
     */
748
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
749
        this.dbfResource.notifyClose();
750
    }
751

    
752
    /**
753
     * @throws ResourceNotifyOpenException
754
     *
755
     */
756
    protected void resourcesOpen() throws ResourceNotifyOpenException {
757
        this.dbfResource.notifyOpen();
758
    }
759

    
760
    public Object getSourceId() {
761
        return this.getDBFParameters().getFile();
762
    }
763

    
764
    public String getName() {
765
        String name = this.getDBFParameters().getFile().getName();
766
        int n = name.lastIndexOf(".");
767
        if (n < 1) {
768
            return name;
769
        }
770
        return name.substring(0, n);
771
    }
772

    
773
    public String getFullName() {
774
        return this.getDBFParameters().getFile().getAbsolutePath();
775
    }
776

    
777
    protected void resourceCloseRequest() throws ResourceException {
778
        this.dbfResource.closeRequest();
779
    }
780

    
781
    public ResourceProvider getResource() {
782
        return dbfResource;
783
    }
784
    
785
    @Override
786
    public void fixFeatureTypeFromParameters() {
787
        FeatureStoreProviderServices store = this.getStoreServices();
788
        try {
789
            int sizeWithoutComputed = 0;
790
            for (FeatureAttributeDescriptor featureAttributeDescriptor : store.getDefaultFeatureType()) {
791
                if (featureAttributeDescriptor.isComputed()) {
792
                    continue;
793
                }
794
                sizeWithoutComputed +=1;
795
            }
796
            if(this.featureType.size()!=sizeWithoutComputed) {
797
                this.setFeatureType(featureType);
798
            }
799
        } catch (DataException ex) {
800
            
801
        }
802
    }
803

    
804
}