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

History | View | Annotate | Download (26.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

    
33
import org.apache.commons.io.FileUtils;
34

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

    
89
import org.slf4j.Logger;
90
import org.slf4j.LoggerFactory;
91

    
92
public class DBFStoreProvider extends AbstractFeatureStoreProvider implements
93
        ResourceConsumer {
94

    
95
    private static final Logger LOG = LoggerFactory.getLogger(DBFStoreProvider.class);
96

    
97
    public static final int MAX_FIELD_NAME_LENGTH = DbaseFile.MAX_FIELD_NAME_LENGTH;
98

    
99
    public static final String NAME = DataStore.DBASE_PROVIDER_NAME;
100
    public static final String DESCRIPTION = "DBF file";
101

    
102
    public static final String METADATA_DEFINITION_NAME = NAME;
103
    private static final String METADATA_ENCODING = "Encoding";
104
    private static final String METADATA_CODEPAGE = "CodePage";
105

    
106
    private DbaseFile dbfFile = null;
107
    private ResourceProvider dbfResource;
108
    private long counterNewsOIDs = -1;
109
    private DBFFeatureWriter writer;
110

    
111
    private boolean loTengoEnUso;
112

    
113
    private boolean allowDuplicatedFieldNames;
114
    private FilteredLogger logger;
115

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

    
127
    public DBFStoreProvider(DBFStoreParameters params,
128
            DataStoreProviderServices storeServices)
129
            throws InitializeException {
130
        this(
131
                params,
132
                storeServices,
133
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
134
        );
135
    }
136

    
137
    protected DBFStoreProvider(DBFStoreParameters params,
138
            DataStoreProviderServices storeServices, DynObject metadata)
139
            throws InitializeException {
140
        super(params, storeServices, metadata);
141
        this.logger = new FilteredLogger(LOG, "DBFStoreProvider", -1);
142
        this.logger.setInterval(2000);
143
        this.init(params, storeServices);
144
    }
145

    
146
    protected void init(DBFStoreParameters params,
147
            DataStoreProviderServices storeServices) throws InitializeException {
148
        if (params == null) {
149
            throw new InitializeException(new NullPointerException("params is null"));
150
        }
151
        File theFile = getDBFParameters().getDBFFile();
152
        if (theFile == null) {
153
            throw new InitializeException(new NullPointerException("dbf file is null"));
154
        }
155
        initResource(params, storeServices);
156

    
157
        Charset charset = params.getEncoding();
158
        allowDuplicatedFieldNames = params.allowDuplicatedFieldNames();
159
        this.dbfFile = new DbaseFile(theFile, charset, allowDuplicatedFieldNames);
160

    
161
        writer = new DBFFeatureWriter(this.getProviderName());
162

    
163
        this.initFeatureType();
164

    
165
    }
166

    
167
    public Object getDynValue(String name) throws DynFieldNotFoundException {
168
        try {
169
            this.open();
170
        } catch (OpenException e) {
171
            throw new RuntimeException(e);
172
        }
173

    
174
        if (METADATA_ENCODING.equalsIgnoreCase(name)) {
175
            return this.dbfFile.getOriginalCharset();
176
        } else if (METADATA_CODEPAGE.equalsIgnoreCase(name)) {
177
            return this.dbfFile.getCodePageInt();
178
        }
179
        return super.getDynValue(name);
180
    }
181

    
182
    protected void initResource(DBFStoreParameters params,
183
            DataStoreProviderServices storeServices) throws InitializeException {
184

    
185
        File theFile = getDBFParameters().getDBFFile();
186
        dbfResource
187
                = this.createResource(FileResource.NAME,
188
                        new Object[]{theFile.getAbsolutePath()});
189
        dbfResource.addConsumer(this);
190
    }
191

    
192
    protected void initResource(ResourceProvider resource,
193
        DataStoreProviderServices storeServices){
194
        dbfResource = resource;
195
        dbfResource.addConsumer(this);
196
    }
197

    
198
    public String getProviderName() {
199
        return NAME;
200
    }
201

    
202
    protected DBFStoreParameters getDBFParameters() {
203
        return (DBFStoreParameters) super.getParameters();
204
    }
205

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

    
219
    protected FeatureProvider internalGetFeatureProviderByReference(
220
            FeatureReferenceProviderServices reference, FeatureType featureType)
221
            throws DataException {
222
        return this.getFeatureProviderByIndex(
223
                ((Number) reference.getOID()).longValue(), featureType);
224
    }
225

    
226
    public void performChanges(Iterator deleteds, Iterator inserteds,
227
            Iterator updateds, Iterator originalFeatureTypesUpdated)
228
            throws PerformEditingException {
229

    
230
        /*
231
         * This will throw an exception if there are new fields
232
         * with names too long
233
         */
234
        checkNewFieldsNameSize(originalFeatureTypesUpdated);
235

    
236
        try {
237
            // TODO repasar el concepto de enUso de un recurso.
238
            loTengoEnUso = true;
239
            final FeatureStore theStore = this.getStoreServices().getFeatureStore();
240
            resourceCloseRequest();
241
            getResource().execute(new ResourceAction() {
242

    
243
                public Object run() throws Exception {
244
                    FeatureSet set = null;
245
                    DisposableIterator iter = null;
246
                    try {
247
                        set = theStore.getFeatureSet();
248
                        DBFStoreParameters tmpParams
249
                                = (DBFStoreParameters) getDBFParameters().getCopy();
250

    
251
                        File tmp_file = File.createTempFile(
252
                                "tmp_" + System.currentTimeMillis(), ".dbf");
253
                        tmp_file.deleteOnExit();
254

    
255
                        tmpParams.setDBFFile(tmp_file);
256

    
257
                        writer.begin(tmpParams, theStore.getDefaultFeatureType(),
258
                                set.getSize());
259

    
260
                        iter = set.fastIterator();
261
                        while (iter.hasNext()) {
262
                            Feature feature = (Feature) iter.next();
263
                            writer.append(feature);
264
                        }
265

    
266
                        writer.end();
267
                        loTengoEnUso = false;
268
                        try {
269
                            close();
270
                        } catch (CloseException e1) {
271
                            throw new PerformEditingException(getProviderName(), e1);
272
                        }
273
                        getDBFParameters().getDBFFile().delete();
274

    
275
                        File target_file = getDBFParameters().getDBFFile();
276
                        if (target_file.exists()) {
277
                            target_file.delete();
278
                        }
279
                        tmp_file.renameTo(target_file);
280

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

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

    
309
        this.counterNewsOIDs = -1;
310
    }
311

    
312
    protected void checkNewFieldsNameSize(Iterator ft_upd) throws PerformEditingException {
313

    
314
        String long_fields = getNewFieldsWithNameTooLong(ft_upd);
315
        if (long_fields != null) {
316
            AttributeNameException ane = new AttributeNameTooLongException(
317
                    long_fields,
318
                    getProviderName(),
319
                    MAX_FIELD_NAME_LENGTH);
320
            throw new PerformEditingException(getProviderName(), ane);
321
        }
322
    }
323

    
324
    /**
325
     * Returns null or a string which is a comma-separated list
326
     *
327
     * @param ft_updated
328
     * @return
329
     */
330
    protected String getNewFieldsWithNameTooLong(Iterator ft_updated) {
331

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

    
351
        if (resp.length() == 0) {
352
            return null;
353
        } else {
354
            return "(" + resp + ")";
355
        }
356
    }
357

    
358
    public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
359
        return new DBFFeatureProvider(this, type);
360
    }
361

    
362
    protected void initFeatureType() throws InitializeException {
363
        FeatureType defaultType = this.getTheFeatureType().getNotEditableCopy();
364
        List types = new ArrayList(1);
365
        types.add(defaultType);
366
        getStoreServices().setFeatureTypes(types, defaultType);
367
    }
368

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

    
395
        if (descriptor.getEvaluator() != null) {
396
            // Nothing to do
397
            return;
398
        }
399

    
400
        int dbfFieldIndex = this.dbfFile.getFieldIndex(descriptor.getName());
401

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

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

    
430
            case DataTypes.DECIMAL:
431
                featureProvider.set(index, 
432
                    formatter.parseDecimal(
433
                        value, 
434
                        descriptor.getMathContext(), 
435
                        descriptor.getScale(),
436
                        (BigDecimal) defaultValue
437
                  )
438
                );
439
                break;
440

    
441
            case DataTypes.DOUBLE:
442
                featureProvider.set(index, formatter.parseDouble(value, (Double) defaultValue));
443
                break;
444

    
445
            case DataTypes.FLOAT:
446
                featureProvider.set(index, formatter.parseFloat(value, (Float) defaultValue));
447
                break;
448

    
449
            case DataTypes.LONG:
450
                featureProvider.set(index, formatter.parseLong(value, (Long) defaultValue));
451
                break;
452

    
453
            case DataTypes.INT:
454
                featureProvider.set(index, formatter.parseInt(value, (Integer) defaultValue));
455
                break;
456

    
457
            case DataTypes.BYTE:
458
                featureProvider.set(index, formatter.parseByte(value, (Byte) defaultValue));
459
                break;
460

    
461
            case DataTypes.BOOLEAN:
462
                featureProvider.set(index, formatter.parseBoolean(value, (Boolean) defaultValue));
463
                break;
464

    
465
            case DataTypes.TIMESTAMP:
466
                featureProvider.set(index, formatter.parseTimestamp(value, (java.sql.Timestamp) defaultValue));
467
                break;
468
                
469
            case DataTypes.TIME:
470
                featureProvider.set(index, formatter.parseTime(value, (java.sql.Time) defaultValue));
471
                break;
472

    
473
            case DataTypes.DATE:
474
                featureProvider.set(index, formatter.parseDate(value, (java.sql.Date) defaultValue));
475
                break;
476

    
477
            default: {
478
                    Object v;
479
                    try {
480
                        v = descriptor.getDataType().coerce(value);
481
                    } catch (CoercionException ex) {
482
                        v = defaultValue;
483
                    }
484
                    featureProvider.set(index, v);
485
                }
486
                break;
487
        }
488
    }
489

    
490
    protected FeatureProvider getFeatureProviderByIndex(long index) throws DataException {
491
        return this
492
                .getFeatureProviderByIndex(index, this.getStoreServices()
493
                        .getDefaultFeatureType());
494
    }
495

    
496
    public long getFeatureCount() throws ReadException, OpenException,
497
            ResourceNotifyChangesException {
498
        this.open();
499
        return (long) getResource().execute(new ResourceAction() {
500
            public Object run() throws Exception {
501
                return (long) dbfFile.getRecordCount();
502
            }
503
        });
504
    }
505

    
506
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
507
            throws DataException {
508
        return new DBFSetProvider(this, query, featureType);
509
    }
510

    
511
    public boolean canCreate() {
512
        return true;
513
    }
514

    
515
    public boolean canWriteGeometry(int geometryType, int geometrySubType) throws DataException {
516
        return false;
517
    }
518

    
519
    public void open() throws OpenException {
520
        if (this.dbfFile.isOpen()) {
521
            return;
522
        }
523
        try {
524
            getResource().execute(new ResourceAction() {
525
                public Object run() throws Exception {
526
                    openFile();
527
                    resourcesOpen();
528
                    return null;
529
                }
530
            });
531

    
532
        } catch (ResourceExecuteException e) {
533
            throw new OpenException(this.getProviderName(), e);
534
        }
535
    }
536

    
537
    protected void openFile() throws FileNotFoundException,
538
            UnsupportedVersionException, IOException, DataException {
539
        this.dbfFile.open();
540
        // necessary when editing the file
541
        this.getDBFParameters().setEffectiveEncoding(this.dbfFile.getCharsetName());
542
    }
543

    
544
    public void close() throws CloseException {
545
        if( loTengoEnUso ) {
546
            return;
547
        }
548
        if (dbfFile == null || !this.dbfFile.isOpen()) {
549
            return;
550
        }
551
        super.close();
552

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

    
567
    protected void closeFile() throws CloseException {
568
        this.dbfFile.close();
569
    }
570

    
571
    @Override
572
    protected void doDispose() throws BaseException {
573
        this.close();
574
        dbfFile = null;
575
        disposeResource();
576
        super.doDispose();
577
    }
578

    
579
    protected void disposeResource() {
580
        this.dbfResource.removeConsumer(this);
581
        dbfResource = null;
582
    }
583

    
584
    public boolean closeResourceRequested(ResourceProvider resource) {
585
        try {
586
            this.close();
587
        } catch (CloseException e) {
588
            return false;
589
        }
590
        return true;
591
    }
592

    
593
    public boolean allowWrite() {
594
        if(allowDuplicatedFieldNames){
595
            return false;
596
        }
597
        return this.dbfFile.isWritable();
598
    }
599

    
600
    public void refresh() throws OpenException {
601
        try {
602
            this.close();
603
        } catch (CloseException e) {
604
            throw new OpenException(this.getProviderName(), e);
605
        }
606
        this.open();
607
        try {
608
            this.initFeatureType();
609
        } catch (InitializeException e) {
610
            throw new OpenException(this.getProviderName(), e);
611
        }
612
    }
613

    
614
    /**
615
     *
616
     * @param index
617
     * @param featureType
618
     * @return
619
     * @throws ReadException
620
     */
621
    protected FeatureProvider getFeatureProviderByIndex(long index,
622
            FeatureType featureType) throws DataException {
623
        FeatureProvider featureProvider = this.createFeatureProvider(featureType);
624
        featureProvider.setOID(index);
625
        return featureProvider;
626
    }
627

    
628
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
629
            long index, FeatureType featureType) throws DataException {
630
        featureProvider.setOID(index);
631
    }
632

    
633
    /**
634
     *
635
     * @param featureProvider
636
     * @throws DataException
637
     */
638
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
639
            throws DataException {
640

    
641
        long index = ((Long) featureProvider.getOID());
642
        int rec_count = this.dbfFile.getRecordCount();
643

    
644
        if (index >= rec_count) {
645

    
646
            ReadException rex = new ReadException(this.getName(),
647
                    new ArrayIndexOutOfBoundsException(
648
                            "Index of requested feature ("
649
                            + index + ") is >= record count (" + rec_count + ")"));
650

    
651
            LOG.info("Error while loading feature. ", rex);
652
            throw rex;
653
        }
654

    
655
        for (FeatureAttributeDescriptor desc : featureProvider.getType()) {
656
            this.loadValue(featureProvider, index, desc);
657
        }
658
    }
659

    
660
    public int getOIDType() {
661
        return DataTypes.LONG;
662
    }
663

    
664
    public Object createNewOID() {
665
        if (this.counterNewsOIDs < 0) {
666
            try {
667
                this.counterNewsOIDs = this.getFeatureCount();
668
            } catch (DataException e) {
669
                LOG.warn("Can't initialice counter for news OIDs.",e);
670
            }
671

    
672
        } else {
673
            this.counterNewsOIDs++;
674
        }
675
        return counterNewsOIDs;
676
    }
677

    
678
    public boolean supportsAppendMode() {
679
        return true;
680
    }
681

    
682
    public void append(final FeatureProvider featureProvider)
683
            throws DataException {
684
        getResource().execute(new ResourceAction() {
685
            public Object run() throws Exception {
686
                writer.append(getStoreServices().createFeature(featureProvider));
687
                return null;
688
            }
689
        });
690
    }
691

    
692
    public void beginAppend() throws DataException {
693
        this.close();
694
        getResource().execute(new ResourceAction() {
695
            public Object run() throws Exception {
696
                writer.begin(getDBFParameters(),
697
                        getStoreServices().getDefaultFeatureType(),
698
                        getStoreServices().getFeatureStore().getFeatureCount());
699
                return null;
700
            }
701
        });
702
    }
703

    
704
    public void endAppend() throws DataException {
705
        getResource().execute(new ResourceAction() {
706
            public Object run() throws Exception {
707
                writer.end();
708
                resourcesNotifyChanges();
709
                counterNewsOIDs = -1;
710
                return null;
711
            }
712
        });
713
    }
714

    
715
    public void resourceChanged(ResourceProvider resource) {
716
        if (this.getStoreServices()!=null){
717
            this.getStoreServices().notifyChange(
718
                    DataStoreNotification.RESOURCE_CHANGED,
719
                    resource);
720
        }
721
    }
722

    
723
    /**
724
     *
725
     * @throws ResourceNotifyChangesException
726
     */
727
    protected void resourcesNotifyChanges()
728
            throws ResourceNotifyChangesException {
729
        this.dbfResource.notifyChanges();
730
    }
731

    
732
    /**
733
     * @throws ResourceNotifyCloseException
734
     *
735
     */
736
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
737
        this.dbfResource.notifyClose();
738
    }
739

    
740
    /**
741
     * @throws ResourceNotifyOpenException
742
     *
743
     */
744
    protected void resourcesOpen() throws ResourceNotifyOpenException {
745
        this.dbfResource.notifyOpen();
746
    }
747

    
748
    public Object getSourceId() {
749
        return this.getDBFParameters().getFile();
750
    }
751

    
752
    public String getName() {
753
        String name = this.getDBFParameters().getFile().getName();
754
        int n = name.lastIndexOf(".");
755
        if (n < 1) {
756
            return name;
757
        }
758
        return name.substring(0, n);
759
    }
760

    
761
    public String getFullName() {
762
        return this.getDBFParameters().getFile().getAbsolutePath();
763
    }
764

    
765
    protected void resourceCloseRequest() throws ResourceException {
766
        this.dbfResource.closeRequest();
767
    }
768

    
769
    public ResourceProvider getResource() {
770
        return dbfResource;
771
    }
772

    
773
}