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

History | View | Annotate | Download (27 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.math.MathContext;
29
import java.math.RoundingMode;
30
import java.nio.charset.Charset;
31
import java.text.SimpleDateFormat;
32
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.Iterator;
35
import java.util.List;
36

    
37
import org.apache.commons.io.FileUtils;
38

    
39
import org.gvsig.fmap.dal.DALLocator;
40
import org.gvsig.fmap.dal.DataManager;
41
import org.gvsig.fmap.dal.DataServerExplorer;
42
import org.gvsig.fmap.dal.DataStore;
43
import org.gvsig.fmap.dal.DataStoreNotification;
44
import org.gvsig.fmap.dal.DataTypes;
45
import org.gvsig.fmap.dal.FileHelper;
46
import org.gvsig.fmap.dal.exception.CloseException;
47
import org.gvsig.fmap.dal.exception.DataException;
48
import org.gvsig.fmap.dal.exception.FileNotFoundException;
49
import org.gvsig.fmap.dal.exception.InitializeException;
50
import org.gvsig.fmap.dal.exception.OpenException;
51
import org.gvsig.fmap.dal.exception.ReadException;
52
import org.gvsig.fmap.dal.exception.UnsupportedVersionException;
53
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
54
import org.gvsig.fmap.dal.feature.EditableFeatureType;
55
import org.gvsig.fmap.dal.feature.Feature;
56
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
57
import org.gvsig.fmap.dal.feature.FeatureQuery;
58
import org.gvsig.fmap.dal.feature.FeatureSet;
59
import org.gvsig.fmap.dal.feature.FeatureStore;
60
import org.gvsig.fmap.dal.feature.FeatureType;
61
import org.gvsig.fmap.dal.feature.exception.AttributeNameException;
62
import org.gvsig.fmap.dal.feature.exception.AttributeNameTooLongException;
63
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
64
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
65
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
66
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
67
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
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
import org.gvsig.tools.dataTypes.CoercionContextDecimal;
95

    
96
public class DBFStoreProvider extends AbstractFeatureStoreProvider implements
97
        ResourceConsumer {
98

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

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

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

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

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

    
115
    private boolean loTengoEnUso;
116

    
117
    private boolean allowDuplicatedFieldNames;
118
    private FilteredLogger logger;
119

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

    
131
    public DBFStoreProvider(DBFStoreParameters params,
132
            DataStoreProviderServices storeServices)
133
            throws InitializeException {
134
        super(
135
                params,
136
                storeServices,
137
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
138
        );
139
        this.logger = new FilteredLogger(LOG, "DBFStoreProvider", -1);
140
        this.logger.setInterval(2000);
141
        this.init(params, storeServices);
142
    }
143

    
144
    protected DBFStoreProvider(DBFStoreParameters params,
145
            DataStoreProviderServices storeServices, DynObject metadata)
146
            throws InitializeException {
147
        super(params, storeServices, metadata);
148
        this.init(params, storeServices);
149
    }
150

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

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

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

    
168
        this.initFeatureType();
169

    
170
    }
171

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
260
                        tmpParams.setDBFFile(tmp_file);
261

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

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

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

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

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

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

    
314
        this.counterNewsOIDs = -1;
315
    }
316

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

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

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

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

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

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

    
367
    protected void initFeatureType() throws InitializeException {
368
        FeatureType defaultType = this.getTheFeatureType().getNotEditableCopy();
369
        List types = new ArrayList(1);
370
        types.add(defaultType);
371
        getStoreServices().setFeatureTypes(types, defaultType);
372
    }
373

    
374
    protected EditableFeatureType getTheFeatureType() throws InitializeException {
375
        try {
376
            this.open();
377
        } catch (DataException e) {
378
            throw new InitializeException(this.getProviderName(), e);
379
        }
380
        EditableFeatureType featureType = (EditableFeatureType) getResource().execute(
381
            new ResourceAction() {
382
                public Object run() throws Exception {
383
                    EditableFeatureType featureType = getStoreServices().createFeatureType(getName());
384
                    featureType.setHasOID(true);
385
                    dbfFile.getHeader().toFeatureType(
386
                            featureType,
387
                            getDBFParameters().handleDatesAsStrings()
388
                    );
389
                    return featureType;
390
                }
391
            }
392
        );
393
        return featureType;
394
    }
395
    
396
    
397
    protected void loadValue(FeatureProvider featureProvider, long rowIndex,
398
            FeatureAttributeDescriptor descriptor) throws ReadException {
399

    
400
        if (descriptor.getEvaluator() != null) {
401
            // Nothing to do
402
            return;
403
        }
404

    
405
        int dbfFieldIndex = this.dbfFile.getFieldIndex(descriptor.getName());
406

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

    
418
        String value = null;
419
        try {
420
            value = this.dbfFile.getStringFieldValue(rowIndex, dbfFieldIndex);
421
        } catch (DataException e) {
422
            throw new ReadException(this.getName(), e);
423
        }
424
        value = value.trim();
425
        FieldFormatter formatter = new FieldFormatter();
426
        
427
        int index = descriptor.getIndex();
428
        Object defaultValue = descriptor.getDefaultValueCoerced();
429
        
430
        switch (descriptor.getType()) {
431
            case DataTypes.STRING:
432
                featureProvider.set(index, formatter.parseString(value, (String) defaultValue));
433
                break;
434

    
435
            case DataTypes.DECIMAL:
436
                featureProvider.set(index, 
437
                    formatter.parseDecimal(
438
                        value, 
439
                        descriptor.getMathContext(), 
440
                        descriptor.getScale(),
441
                        (BigDecimal) defaultValue
442
                  )
443
                );
444
                break;
445

    
446
            case DataTypes.DOUBLE:
447
                featureProvider.set(index, formatter.parseDouble(value, (Double) defaultValue));
448
                break;
449

    
450
            case DataTypes.FLOAT:
451
                featureProvider.set(index, formatter.parseFloat(value, (Float) defaultValue));
452
                break;
453

    
454
            case DataTypes.LONG:
455
                featureProvider.set(index, formatter.parseLong(value, (Long) defaultValue));
456
                break;
457

    
458
            case DataTypes.INT:
459
                featureProvider.set(index, formatter.parseInt(value, (Integer) defaultValue));
460
                break;
461

    
462
            case DataTypes.BYTE:
463
                featureProvider.set(index, formatter.parseByte(value, (Byte) defaultValue));
464
                break;
465

    
466
            case DataTypes.BOOLEAN:
467
                featureProvider.set(index, formatter.parseBoolean(value, (Boolean) defaultValue));
468
                break;
469

    
470
            case DataTypes.TIMESTAMP:
471
                featureProvider.set(index, formatter.parseTimestamp(value, (java.sql.Timestamp) defaultValue));
472
                break;
473
                
474
            case DataTypes.TIME:
475
                featureProvider.set(index, formatter.parseTime(value, (java.sql.Time) defaultValue));
476
                break;
477

    
478
            case DataTypes.DATE:
479
                featureProvider.set(index, formatter.parseDate(value, (java.sql.Date) defaultValue));
480
                break;
481

    
482
            default: {
483
                    Object v;
484
                    try {
485
                        v = descriptor.getDataType().coerce(value);
486
                    } catch (CoercionException ex) {
487
                        v = defaultValue;
488
                    }
489
                    featureProvider.set(index, v);
490
                }
491
                break;
492
        }
493
    }
494

    
495
    protected FeatureProvider getFeatureProviderByIndex(long index) throws DataException {
496
        return this
497
                .getFeatureProviderByIndex(index, this.getStoreServices()
498
                        .getDefaultFeatureType());
499
    }
500

    
501
    public long getFeatureCount() throws ReadException, OpenException,
502
            ResourceNotifyChangesException {
503
        this.open();
504
        return (long) getResource().execute(new ResourceAction() {
505
            public Object run() throws Exception {
506
                return (long) dbfFile.getRecordCount();
507
            }
508
        });
509
    }
510

    
511
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
512
            throws DataException {
513
        return new DBFSetProvider(this, query, featureType);
514
    }
515

    
516
    public boolean canCreate() {
517
        return true;
518
    }
519

    
520
    public boolean canWriteGeometry(int geometryType, int geometrySubType) throws DataException {
521
        return false;
522
    }
523

    
524
    public void open() throws OpenException {
525
        if (this.dbfFile.isOpen()) {
526
            return;
527
        }
528
        try {
529
            getResource().execute(new ResourceAction() {
530
                public Object run() throws Exception {
531
                    openFile();
532
                    resourcesOpen();
533
                    return null;
534
                }
535
            });
536

    
537
        } catch (ResourceExecuteException e) {
538
            throw new OpenException(this.getProviderName(), e);
539
        }
540
    }
541

    
542
    protected void openFile() throws FileNotFoundException,
543
            UnsupportedVersionException, IOException, DataException {
544
        this.dbfFile.open();
545
        // necessary when editing the file
546
        this.getDBFParameters().setEffectiveEncoding(this.dbfFile.getCharsetName());
547
    }
548

    
549
    public void close() throws CloseException {
550
        if( loTengoEnUso ) {
551
            return;
552
        }
553
        if (dbfFile == null || !this.dbfFile.isOpen()) {
554
            return;
555
        }
556
        super.close();
557

    
558
        //Cerrar recurso
559
        try {
560
            getResource().execute(new ResourceAction() {
561
                public Object run() throws Exception {
562
                    closeFile();
563
                    resourcesNotifyClose();
564
                    return null;
565
                }
566
            });
567
        } catch (ResourceExecuteException  e) {
568
            throw new CloseException(this.getProviderName(), e);
569
        }
570
    }
571

    
572
    protected void closeFile() throws CloseException {
573
        this.dbfFile.close();
574
    }
575

    
576
    @Override
577
    protected void doDispose() throws BaseException {
578
        this.close();
579
        dbfFile = null;
580
        disposeResource();
581
        super.doDispose();
582
    }
583

    
584
    protected void disposeResource() {
585
        this.dbfResource.removeConsumer(this);
586
        dbfResource = null;
587
    }
588

    
589
    public boolean closeResourceRequested(ResourceProvider resource) {
590
        try {
591
            this.close();
592
        } catch (CloseException e) {
593
            return false;
594
        }
595
        return true;
596
    }
597

    
598
    public boolean allowWrite() {
599
        if(allowDuplicatedFieldNames){
600
            return false;
601
        }
602
        return this.dbfFile.isWritable();
603
    }
604

    
605
    public void refresh() throws OpenException {
606
        try {
607
            this.close();
608
        } catch (CloseException e) {
609
            throw new OpenException(this.getProviderName(), e);
610
        }
611
        this.open();
612
        try {
613
            this.initFeatureType();
614
        } catch (InitializeException e) {
615
            throw new OpenException(this.getProviderName(), e);
616
        }
617
    }
618

    
619
    /**
620
     *
621
     * @param index
622
     * @param featureType
623
     * @return
624
     * @throws ReadException
625
     */
626
    protected FeatureProvider getFeatureProviderByIndex(long index,
627
            FeatureType featureType) throws DataException {
628
        FeatureProvider featureProvider = this.createFeatureProvider(featureType);
629
        featureProvider.setOID(index);
630
        return featureProvider;
631
    }
632

    
633
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
634
            long index, FeatureType featureType) throws DataException {
635
        featureProvider.setOID(index);
636
    }
637

    
638
    /**
639
     *
640
     * @param featureProvider
641
     * @throws DataException
642
     */
643
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
644
            throws DataException {
645

    
646
        long index = ((Long) featureProvider.getOID());
647
        int rec_count = this.dbfFile.getRecordCount();
648

    
649
        if (index >= rec_count) {
650

    
651
            ReadException rex = new ReadException(this.getName(),
652
                    new ArrayIndexOutOfBoundsException(
653
                            "Index of requested feature ("
654
                            + index + ") is >= record count (" + rec_count + ")"));
655

    
656
            LOG.info("Error while loading feature. ", rex);
657
            throw rex;
658
        }
659

    
660
        for (FeatureAttributeDescriptor desc : featureProvider.getType()) {
661
            this.loadValue(featureProvider, index, desc);
662
        }
663
    }
664

    
665
    public int getOIDType() {
666
        return DataTypes.LONG;
667
    }
668

    
669
    public Object createNewOID() {
670
        if (this.counterNewsOIDs < 0) {
671
            try {
672
                this.counterNewsOIDs = this.getFeatureCount();
673
            } catch (DataException e) {
674
                LOG.warn("Can't initialice counter for news OIDs.",e);
675
            }
676

    
677
        } else {
678
            this.counterNewsOIDs++;
679
        }
680
        return counterNewsOIDs;
681
    }
682

    
683
    public boolean supportsAppendMode() {
684
        return true;
685
    }
686

    
687
    public void append(final FeatureProvider featureProvider)
688
            throws DataException {
689
        getResource().execute(new ResourceAction() {
690
            public Object run() throws Exception {
691
                writer.append(getStoreServices().createFeature(featureProvider));
692
                return null;
693
            }
694
        });
695
    }
696

    
697
    public void beginAppend() throws DataException {
698
        this.close();
699
        getResource().execute(new ResourceAction() {
700
            public Object run() throws Exception {
701
                writer.begin(getDBFParameters(),
702
                        getStoreServices().getDefaultFeatureType(),
703
                        getStoreServices().getFeatureStore().getFeatureCount());
704
                return null;
705
            }
706
        });
707
    }
708

    
709
    public void endAppend() throws DataException {
710
        getResource().execute(new ResourceAction() {
711
            public Object run() throws Exception {
712
                writer.end();
713
                resourcesNotifyChanges();
714
                counterNewsOIDs = -1;
715
                return null;
716
            }
717
        });
718
    }
719

    
720
    public void resourceChanged(ResourceProvider resource) {
721
        if (this.getStoreServices()!=null){
722
            this.getStoreServices().notifyChange(
723
                    DataStoreNotification.RESOURCE_CHANGED,
724
                    resource);
725
        }
726
    }
727

    
728
    /**
729
     *
730
     * @throws ResourceNotifyChangesException
731
     */
732
    protected void resourcesNotifyChanges()
733
            throws ResourceNotifyChangesException {
734
        this.dbfResource.notifyChanges();
735
    }
736

    
737
    /**
738
     * @throws ResourceNotifyCloseException
739
     *
740
     */
741
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
742
        this.dbfResource.notifyClose();
743
    }
744

    
745
    /**
746
     * @throws ResourceNotifyOpenException
747
     *
748
     */
749
    protected void resourcesOpen() throws ResourceNotifyOpenException {
750
        this.dbfResource.notifyOpen();
751
    }
752

    
753
    public Object getSourceId() {
754
        return this.getDBFParameters().getFile();
755
    }
756

    
757
    public String getName() {
758
        String name = this.getDBFParameters().getFile().getName();
759
        int n = name.lastIndexOf(".");
760
        if (n < 1) {
761
            return name;
762
        }
763
        return name.substring(0, n);
764
    }
765

    
766
    public String getFullName() {
767
        return this.getDBFParameters().getFile().getAbsolutePath();
768
    }
769

    
770
    protected void resourceCloseRequest() throws ResourceException {
771
        this.dbfResource.closeRequest();
772
    }
773

    
774
    public ResourceProvider getResource() {
775
        return dbfResource;
776
    }
777

    
778
}