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

History | View | Annotate | Download (31.7 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.nio.charset.Charset;
28
import java.text.DateFormat;
29
import java.text.ParseException;
30
import java.text.SimpleDateFormat;
31
import java.util.ArrayList;
32
import java.util.Date;
33
import java.util.Iterator;
34
import java.util.List;
35
import java.util.Locale;
36

    
37
import org.apache.commons.io.FileUtils;
38
import org.apache.commons.lang3.StringUtils;
39
import org.slf4j.Logger;
40
import org.slf4j.LoggerFactory;
41

    
42
import org.gvsig.fmap.dal.DALLocator;
43
import org.gvsig.fmap.dal.DataManager;
44
import org.gvsig.fmap.dal.DataServerExplorer;
45
import org.gvsig.fmap.dal.DataStoreNotification;
46
import org.gvsig.fmap.dal.DataTypes;
47
import org.gvsig.fmap.dal.FileHelper;
48
import org.gvsig.fmap.dal.exception.CloseException;
49
import org.gvsig.fmap.dal.exception.DataException;
50
import org.gvsig.fmap.dal.exception.FileNotFoundException;
51
import org.gvsig.fmap.dal.exception.InitializeException;
52
import org.gvsig.fmap.dal.exception.OpenException;
53
import org.gvsig.fmap.dal.exception.ReadException;
54
import org.gvsig.fmap.dal.exception.UnsupportedVersionException;
55
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
56
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
57
import org.gvsig.fmap.dal.feature.EditableFeatureType;
58
import org.gvsig.fmap.dal.feature.Feature;
59
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
60
import org.gvsig.fmap.dal.feature.FeatureQuery;
61
import org.gvsig.fmap.dal.feature.FeatureSet;
62
import org.gvsig.fmap.dal.feature.FeatureStore;
63
import org.gvsig.fmap.dal.feature.FeatureType;
64
import org.gvsig.fmap.dal.feature.exception.AttributeNameException;
65
import org.gvsig.fmap.dal.feature.exception.AttributeNameTooLongException;
66
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
67
import org.gvsig.fmap.dal.feature.exception.UnknownDataTypeException;
68
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
69
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
70
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
71
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
72
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider.FeatureTypeChanged;
73
import org.gvsig.fmap.dal.resource.ResourceAction;
74
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
75
import org.gvsig.fmap.dal.resource.exception.ResourceException;
76
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
77
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
78
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
79
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
80
import org.gvsig.fmap.dal.resource.file.FileResource;
81
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
82
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
83
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
84
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
85
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
86
import org.gvsig.fmap.dal.store.dbf.utils.DbaseFile;
87
import org.gvsig.metadata.MetadataLocator;
88
import org.gvsig.metadata.MetadataManager;
89
import org.gvsig.metadata.exceptions.MetadataException;
90
import org.gvsig.tools.dispose.DisposableIterator;
91
import org.gvsig.tools.dynobject.DynObject;
92
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
93
import org.gvsig.tools.exception.BaseException;
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 String NAME = "DBF";
103
    public static String DESCRIPTION = "DBF file";
104
    private static final Locale ukLocale = new Locale("en", "UK");
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 static long lastLogTime = 0;
116

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

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

    
139
    protected DBFStoreProvider(DBFStoreParameters params,
140
            DataStoreProviderServices storeServices, DynObject metadata)
141
            throws InitializeException {
142
        super(params, storeServices, metadata);
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
        this.dbfFile = new DbaseFile(theFile, charset);
159

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

    
162
        this.initFeatureType();
163

    
164
    }
165

    
166
    public Object getDynValue(String name) throws DynFieldNotFoundException {
167
        try {
168
            this.open();
169
        } catch (OpenException e) {
170
            throw new RuntimeException(e);
171
        }
172
        if (METADATA_ENCODING.equalsIgnoreCase(name)) {
173
            return this.dbfFile.getOriginalCharset();
174
        } else if (METADATA_CODEPAGE.equalsIgnoreCase(name)) {
175
            return new Byte(this.dbfFile.getCodePage());
176
        }
177
        return super.getDynValue(name);
178
    }
179

    
180
    protected void initResource(DBFStoreParameters params,
181
            DataStoreProviderServices storeServices) throws InitializeException {
182

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

    
190
    public String getProviderName() {
191
        return NAME;
192
    }
193

    
194
    protected DBFStoreParameters getDBFParameters() {
195
        return (DBFStoreParameters) super.getParameters();
196
    }
197

    
198
    public DataServerExplorer getExplorer() throws ReadException {
199
        DataManager manager = DALLocator.getDataManager();
200
        FilesystemServerExplorerParameters params;
201
        try {
202
            params = (FilesystemServerExplorerParameters) manager
203
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
204
            params.setRoot(this.getDBFParameters().getDBFFile().getParent());
205
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
206
        } catch (DataException e) {
207
            throw new ReadException(this.getProviderName(), e);
208
        } catch (ValidateDataParametersException e) {
209
            // TODO Auto-generated catch block
210
            throw new ReadException(this.getProviderName(), e);
211
        }
212
    }
213

    
214
    protected FeatureProvider internalGetFeatureProviderByReference(
215
            FeatureReferenceProviderServices reference, FeatureType featureType)
216
            throws DataException {
217
        return this.getFeatureProviderByIndex(
218
                ((Long) reference.getOID()).longValue(), featureType);
219
    }
220

    
221
    public void performChanges(Iterator deleteds, Iterator inserteds,
222
            Iterator updateds, Iterator originalFeatureTypesUpdated)
223
            throws PerformEditingException {
224

    
225
        /*
226
         * This will throw an exception if there are new fields
227
         * with names too long
228
         */
229
        checkNewFieldsNameSize(originalFeatureTypesUpdated);
230

    
231
        try {
232
            final FeatureStore store
233
                    = this.getStoreServices().getFeatureStore();
234
            getResource().execute(new ResourceAction() {
235

    
236
                public Object run() throws Exception {
237
                    FeatureSet set = null;
238
                    DisposableIterator iter = null;
239
                    try {
240
                        set = store.getFeatureSet();
241
                        DBFStoreParameters tmpParams
242
                                = (DBFStoreParameters) getDBFParameters().getCopy();
243

    
244
                        File tmp_file = File.createTempFile(
245
                                "tmp_" + System.currentTimeMillis(), ".dbf");
246
                        tmp_file.deleteOnExit();
247

    
248
                        tmpParams.setDBFFile(tmp_file);
249

    
250
                        writer.begin(tmpParams, store.getDefaultFeatureType(),
251
                                set.getSize());
252

    
253
                        iter = set.fastIterator();
254
                        while (iter.hasNext()) {
255
                            Feature feature = (Feature) iter.next();
256
                            writer.append(feature);
257
                        }
258

    
259
                        writer.end();
260

    
261
                        try {
262
                            close();
263
                        } catch (CloseException e1) {
264
                            throw new PerformEditingException(getProviderName(), e1);
265
                        }
266
                        getDBFParameters().getDBFFile().delete();
267

    
268
                        File target_file = getDBFParameters().getDBFFile();
269
                        if (target_file.exists()) {
270
                            target_file.delete();
271
                        }
272
                        tmp_file.renameTo(target_file);
273

    
274
                        if (tmp_file.exists() && !target_file.exists()) {
275
                            // Renaming failed, let's simply copy.
276
                            // We assume we cannot delete it, but we
277
                            // used deleteOnExit and it's
278
                            // temporary, so no problem
279
                            LOG.info("Warning: copying tmp file instead of renaming: "
280
                                    + target_file.getName());
281
                            FileUtils.copyFile(tmp_file, target_file);
282
                        }
283

    
284
                        resourcesNotifyChanges();
285
                        initFeatureType();
286
                    } finally {
287
                        if (set != null) {
288
                            set.dispose();
289
                        }
290
                        if (iter != null) {
291
                            iter.dispose();
292
                        }
293
                    }
294
                    return null;
295
                }
296
            });
297
        } catch (ResourceExecuteException e) {
298
            throw new PerformEditingException(this.getProviderName(), e);
299
        }
300

    
301
        this.counterNewsOIDs = -1;
302
    }
303

    
304
    protected void checkNewFieldsNameSize(Iterator ft_upd) throws PerformEditingException {
305

    
306
        String long_fields = getNewFieldsWithNameTooLong(ft_upd);
307
        if (long_fields != null) {
308
            AttributeNameException ane = new AttributeNameTooLongException(
309
                    long_fields,
310
                    getProviderName(),
311
                    MAX_FIELD_NAME_LENGTH);
312
            throw new PerformEditingException(getProviderName(), ane);
313
        }
314
    }
315

    
316
    /**
317
     * Returns null or a string which is a comma-separated list
318
     *
319
     * @param ft_updated
320
     * @return
321
     */
322
    protected String getNewFieldsWithNameTooLong(Iterator ft_updated) {
323

    
324
        String resp = "";
325
        FeatureTypeChanged item = null;
326
        FeatureType ft = null;
327
        FeatureAttributeDescriptor[] atts = null;
328
        while (ft_updated.hasNext()) {
329
            item = (FeatureTypeChanged) ft_updated.next();
330
            ft = item.getTarget();
331
            atts = ft.getAttributeDescriptors();
332
            for (int i = 0; i < atts.length; i++) {
333
                if (atts[i].getName().length() > MAX_FIELD_NAME_LENGTH) {
334
                    if (resp.length() == 0) {
335
                        resp = atts[i].getName();
336
                    } else {
337
                        resp = resp + ", " + atts[i].getName();
338
                    }
339
                }
340
            }
341
        }
342

    
343
        if (resp.length() == 0) {
344
            return null;
345
        } else {
346
            return "(" + resp + ")";
347
        }
348
    }
349
    /*
350
     * ==================================================
351
     */
352

    
353
    public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
354
        return new DBFFeatureProvider(this, type);
355
    }
356

    
357

    
358
    /*
359
     * ===================================================
360
     */
361
    protected void initFeatureType() throws InitializeException {
362
        try {
363
            FeatureType defaultType
364
                    = this.getTheFeatureType().getNotEditableCopy();
365
            List types = new ArrayList(1);
366
            types.add(defaultType);
367
            this.getStoreServices().setFeatureTypes(types, defaultType);
368
        } catch (OpenException e) {
369
            throw new InitializeException(getResource().toString(), e);
370
        }
371
    }
372

    
373
    protected EditableFeatureType getTheFeatureType()
374
            throws InitializeException, OpenException {
375
        try {
376
            this.open();
377
        } catch (DataException e) {
378
            throw new InitializeException(this.getProviderName(), e);
379
        }
380
        return (EditableFeatureType) getResource().execute(
381
                new ResourceAction() {
382

    
383
                    public Object run() throws Exception {
384
                        int fieldCount = -1;
385
                        fieldCount = dbfFile.getFieldCount();
386

    
387
                        EditableFeatureType fType = getStoreServices().createFeatureType(getName());
388

    
389
                        fType.setHasOID(true);
390
                        int precision;
391
                        for (int i = 0; i < fieldCount; i++) {
392
                            char fieldType = dbfFile.getFieldType(i);
393
                            EditableFeatureAttributeDescriptor attr;
394

    
395
                            if (fieldType == 'L') {
396
                                attr = fType.add(dbfFile.getFieldName(i), DataTypes.BOOLEAN);
397
                                attr.setDefaultValue(new Boolean(false));
398
                                attr.setAllowNull(false);
399

    
400
                            } else if ((fieldType == 'F') || (fieldType == 'N')) {
401
                                precision = dbfFile.getFieldDecimalLength(i);
402
                                if (precision > 0) {
403
                                    attr = fType.add(dbfFile.getFieldName(i),
404
                                            DataTypes.DOUBLE,
405
                                            dbfFile.getFieldLength(i));
406
                                    attr.setPrecision(precision);
407
                                    attr.setDefaultValue(new Double(0));
408

    
409
                                } else {
410
                                    int length = dbfFile.getFieldLength(i);
411
                                    int type = DataTypes.INT;
412
                                    if (length > 9) {
413
                                        type = DataTypes.LONG;
414
                                    }
415
                                    attr = fType.add(dbfFile.getFieldName(i),
416
                                            type,
417
                                            length);
418
                                    attr.setDefaultValue(new Integer(0));
419
                                }
420
                                attr.setAllowNull(false);
421

    
422
                            } else if (fieldType == 'C' || getDBFParameters().handleDatesAsStrings()) {
423
                                attr = fType.add(dbfFile.getFieldName(i), DataTypes.STRING);
424
                                attr.setSize(dbfFile.getFieldLength(i));
425
                                attr.setDefaultValue("");
426
                                attr.setAllowNull(false);
427

    
428
                            } else if (fieldType == 'D') {
429
                                attr = fType.add(dbfFile.getFieldName(i), DataTypes.DATE);
430
                                attr.setDefaultValue(new Date(0)); // def value 1-1-1970
431
                                attr.setAllowNull(true);
432
                                String sfmt = getDBFParameters().getDateFormat();
433
                                if (!StringUtils.isBlank(sfmt)) {
434
                                    try {
435
                                        SimpleDateFormat datefmt = new SimpleDateFormat(sfmt, getDBFParameters().getLocale());
436
                                        attr.setDateFormat(datefmt);
437
                                    } catch (Exception ex) {
438
                                        LOG.warn("Invalid date format ("+sfmt+") specified in DBF parameters.",ex);
439
                                    }
440
                                }
441
                            } else {
442
                                throw new InitializeException(getProviderName(),
443
                                        new UnknownDataTypeException(
444
                                                dbfFile.getFieldName(i), ""
445
                                                + fieldType, getProviderName()));
446
                            }
447
                        }
448

    
449
                        // FeatureRules rules = fType.getRules();
450
                        // rules.add(new DBFRowValidator());
451
                        return fType;
452
                    }
453
                }
454
        );
455
    }
456

    
457
    protected void loadValue(FeatureProvider featureProvider, int rowIndex,
458
            FeatureAttributeDescriptor descriptor) throws ReadException {
459

    
460
        if (descriptor.getEvaluator() != null) {
461
            // Nothing to do
462
            return;
463
        }
464

    
465
        int dbfIndex = this.dbfFile.getFieldIndex(descriptor.getName());
466

    
467
        if (dbfIndex < 0) {
468
            // Someone asked to load a field
469
            // which does not exist in the DBF file. This can happen 
470
            // in editing process when a field has been added
471
            // in the current editing session, so we simply do nothing.
472
            // The expansion manager is expected to manage those new fields
473
            // and their values.
474
            long curr_time = System.currentTimeMillis();
475
            // This ensures not more than one log every 2 seconds
476
            if (curr_time - lastLogTime > 2000) {
477
                LOG.info("Warning: The requested field does not exist in the DBF file. Assumed it's a new field in editing mode.");
478
                lastLogTime = curr_time;
479
            }
480
            return;
481
        }
482

    
483
        String value = null;
484
        try {
485
            value = this.dbfFile.getStringFieldValue(rowIndex, dbfIndex);
486
        } catch (DataException e) {
487
            throw new ReadException(this.getProviderName(), e);
488
        }
489
        value = value.trim();
490
        int fieldType = descriptor.getType();
491
        switch (fieldType) {
492
            case DataTypes.STRING:
493
                featureProvider.set(descriptor.getIndex(), value);
494
                break;
495

    
496
            case DataTypes.DOUBLE:
497
                try {
498
                    featureProvider.set(descriptor.getIndex(), new Double(value));
499
                } catch (NumberFormatException e) {
500
                    featureProvider.set(descriptor.getIndex(), null);
501
                }
502
                break;
503

    
504
            case DataTypes.INT:
505
                try {
506
                    featureProvider.set(descriptor.getIndex(), new Integer(value));
507
                } catch (NumberFormatException e) {
508
                    featureProvider.set(descriptor.getIndex(), null);
509
                }
510
                break;
511

    
512
            case DataTypes.FLOAT:
513
                try {
514
                    featureProvider.set(descriptor.getIndex(), new Float(value));
515
                } catch (NumberFormatException e) {
516
                    featureProvider.set(descriptor.getIndex(), null);
517
                }
518
                break;
519

    
520
            case DataTypes.LONG:
521
                try {
522
                    featureProvider.set(descriptor.getIndex(), new Long(value));
523
                } catch (NumberFormatException e) {
524
                    featureProvider.set(descriptor.getIndex(), null);
525
                }
526
                break;
527

    
528
            case DataTypes.BOOLEAN:
529
                if (value.equalsIgnoreCase("T")) {
530
                    featureProvider.set(descriptor.getIndex(), Boolean.TRUE);
531
                } else {
532
                    featureProvider.set(descriptor.getIndex(), Boolean.FALSE);
533

    
534
                }
535
                break;
536

    
537
            case DataTypes.BYTE:
538
                try {
539
                    featureProvider.set(descriptor.getIndex(), new Byte(value));
540
                } catch (NumberFormatException e) {
541
                    featureProvider.set(descriptor.getIndex(), null);
542
                }
543
                break;
544

    
545
            case DataTypes.DATE:
546
                if (value.equals("")) {
547
                    value = null;
548
                    return;
549
                }
550
                Date dat = null;
551
                DateFormat df = new SimpleDateFormat("yyyyMMdd");
552
                try {
553
                    dat = df.parse(value);
554
                } catch (ParseException e) {
555
                    throw new InvalidDateException(df.toString(), value, this.getProviderName(), e);
556
                }
557
                featureProvider.set(descriptor.getIndex(), dat);
558
                break;
559

    
560
            default:
561
                featureProvider
562
                        .set(descriptor.getIndex(), descriptor.getDefaultValue());
563
                break;
564
        }
565
    }
566

    
567
    private static class InvalidDateException extends ReadException {
568
        public InvalidDateException(String dateFormat, String value, String store, Throwable cause) {
569
            super(
570
                    "Can't parse date value '%(value)' with format '%(dateFormat)' in dbf '%(store)'.",
571
                    cause,
572
                    "Cant_parse_date_value_XvalueX_with_format_XdateFormatX_in_dbf_XstoreX",
573
                    0
574
            );
575
            setValue("dateFormat",dateFormat);
576
            setValue("value", value);
577
            setValue("store",store);   
578
        }
579
    }
580
    
581
    /**
582
     * *
583
     * NOT supported in Alter Mode
584
     *
585
     * @param index
586
     * @return
587
     * @throws ReadException
588
     */
589
    protected FeatureProvider getFeatureProviderByIndex(long index) throws DataException {
590
        return this
591
                .getFeatureProviderByIndex(index, this.getStoreServices()
592
                        .getDefaultFeatureType());
593
    }
594

    
595
    public long getFeatureCount() throws ReadException, OpenException,
596
            ResourceNotifyChangesException {
597
        this.open();
598
        return ((Long) getResource().execute(new ResourceAction() {
599
            public Object run() throws Exception {
600
                return Long.valueOf(dbfFile.getRecordCount());
601
            }
602
        })).longValue();
603
    }
604

    
605
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
606
            throws DataException {
607
        return new DBFSetProvider(this, query, featureType);
608
    }
609

    
610
    public boolean canCreate() {
611
        return true;
612
    }
613

    
614
    public boolean canWriteGeometry(int geometryType, int geometrySubType) throws DataException {
615
        return false;
616
    }
617

    
618
    public void open() throws OpenException {
619
        if (this.dbfFile.isOpen()) {
620
            return;
621
        }
622
        try {
623
            getResource().execute(new ResourceAction() {
624
                public Object run() throws Exception {
625
                    openFile();
626
                    resourcesOpen();
627
                    return null;
628
                }
629
            });
630

    
631
        } catch (ResourceExecuteException e) {
632
            throw new OpenException(this.getProviderName(), e);
633
        }
634
    }
635

    
636
    protected void openFile() throws FileNotFoundException,
637
            UnsupportedVersionException, IOException, DataException {
638
        this.dbfFile.open();
639
    }
640

    
641
    public void close() throws CloseException {
642
        if (dbfFile == null || !this.dbfFile.isOpen()) {
643
            return;
644
        }
645
        super.close();
646
        //Cerrar recurso
647
        try {
648
            getResource().execute(new ResourceAction() {
649
                public Object run() throws Exception {
650
                    closeFile();
651
                    resourcesNotifyClose();
652
                    return null;
653
                }
654
            });
655
        } catch (ResourceExecuteException e) {
656
            throw new CloseException(this.getProviderName(), e);
657
        }
658
    }
659

    
660
    protected void closeFile() throws CloseException {
661
        this.dbfFile.close();
662
    }
663

    
664
    @Override
665
    protected void doDispose() throws BaseException {
666
        this.close();
667
        dbfFile = null;
668
        disposeResource();
669
        super.doDispose();
670
    }
671

    
672
    protected void disposeResource() {
673
        this.dbfResource.removeConsumer(this);
674
        dbfResource = null;
675
    }
676

    
677
    public boolean closeResourceRequested(ResourceProvider resource) {
678
        try {
679
            this.close();
680
        } catch (CloseException e) {
681
            return false;
682
        }
683
        return true;
684
    }
685

    
686
    public boolean allowWrite() {
687
        File file;
688
        try {
689
            file = ((File) this.dbfResource.get());
690
        } catch (AccessResourceException e) {
691
            return false;
692
        }
693
        return file.canWrite();
694
    }
695

    
696
    public void refresh() throws OpenException {
697
        try {
698
            this.close();
699
        } catch (CloseException e) {
700
            throw new OpenException(this.getProviderName(), e);
701
        }
702
        this.open();
703
        try {
704
            this.initFeatureType();
705
        } catch (InitializeException e) {
706
            throw new OpenException(this.getProviderName(), e);
707
        }
708
    }
709

    
710
    /**
711
     *
712
     * @param index
713
     * @param featureType
714
     * @return
715
     * @throws ReadException
716
     */
717
    protected FeatureProvider getFeatureProviderByIndex(long index,
718
            FeatureType featureType) throws DataException {
719
        FeatureProvider featureProvider = this.createFeatureProvider(featureType);
720
        featureProvider.setOID(new Long(index));
721
        return featureProvider;
722
    }
723

    
724
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
725
            long index, FeatureType featureType) throws DataException {
726
        featureProvider.setOID(new Long(index));
727
    }
728

    
729
    /**
730
     *
731
     * @param featureProvider
732
     * @throws DataException
733
     */
734
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
735
            throws DataException {
736

    
737
        long index = ((Long) featureProvider.getOID()).longValue();
738
        int rec_count = this.dbfFile.getRecordCount();
739

    
740
        if (index >= rec_count) {
741

    
742
            ReadException rex = new ReadException(NAME,
743
                    new ArrayIndexOutOfBoundsException(
744
                            "Index of requested feature ("
745
                            + index + ") is >= record count (" + rec_count + ")"));
746

    
747
            LOG.info("Error while loading feature. ", rex);
748
            throw rex;
749
        }
750

    
751
        Iterator iterator = featureProvider.getType().iterator();
752
        while (iterator.hasNext()) {
753
            FeatureAttributeDescriptor descriptor
754
                    = (FeatureAttributeDescriptor) iterator.next();
755
            this.loadValue(featureProvider, (int) index, descriptor);
756
        }
757
    }
758

    
759
    public int getOIDType() {
760
        return DataTypes.LONG;
761
    }
762

    
763
    public Object createNewOID() {
764
        if (this.counterNewsOIDs < 0) {
765
            try {
766
                this.counterNewsOIDs = this.getFeatureCount();
767
            } catch (DataException e) {
768
                e.printStackTrace();
769
            }
770

    
771
        } else {
772
            this.counterNewsOIDs++;
773
        }
774
        return new Long(counterNewsOIDs);
775
    }
776

    
777
    public boolean supportsAppendMode() {
778
        return true;
779
    }
780

    
781
    public void append(final FeatureProvider featureProvider)
782
            throws DataException {
783
        getResource().execute(new ResourceAction() {
784
            public Object run() throws Exception {
785
                writer.append(getStoreServices().createFeature(featureProvider));
786
                return null;
787
            }
788
        });
789
    }
790

    
791
    public void beginAppend() throws DataException {
792
        this.close();
793
        getResource().execute(new ResourceAction() {
794
            public Object run() throws Exception {
795
                writer.begin(getDBFParameters(),
796
                        getStoreServices().getDefaultFeatureType(),
797
                        getStoreServices().getFeatureStore().getFeatureCount());
798
                return null;
799
            }
800
        });
801
    }
802

    
803
    public void endAppend() throws DataException {
804
        getResource().execute(new ResourceAction() {
805
            public Object run() throws Exception {
806
                writer.end();
807
                resourcesNotifyChanges();
808
                counterNewsOIDs = -1;
809
                return null;
810
            }
811
        });
812
    }
813

    
814
    /*
815
     * (non-Javadoc)
816
     *
817
     * @see
818
     * org.gvsig.fmap.dal.resource.spi.ResourceConsumer#resourceChanged(org.
819
     * gvsig.fmap.dal.resource.spi.ResourceProvider)
820
     */
821
    public void resourceChanged(ResourceProvider resource) {
822
        this.getStoreServices().notifyChange(
823
                DataStoreNotification.RESOURCE_CHANGED,
824
                resource);
825
    }
826

    
827
    /**
828
     *
829
     * @throws ResourceNotifyChangesException
830
     */
831
    protected void resourcesNotifyChanges()
832
            throws ResourceNotifyChangesException {
833
        this.dbfResource.notifyChanges();
834
    }
835

    
836
    /**
837
     * @throws ResourceNotifyCloseException
838
     *
839
     */
840
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
841
        this.dbfResource.notifyClose();
842
    }
843

    
844
    /**
845
     * @throws ResourceNotifyOpenException
846
     *
847
     */
848
    protected void resourcesOpen() throws ResourceNotifyOpenException {
849
        this.dbfResource.notifyOpen();
850
    }
851

    
852
    public Object getSourceId() {
853
        return this.getDBFParameters().getFile();
854
    }
855

    
856
    public String getName() {
857
        String name = this.getDBFParameters().getFile().getName();
858
        int n = name.lastIndexOf(".");
859
        if (n < 1) {
860
            return name;
861
        }
862
        return name.substring(0, n);
863
    }
864

    
865
    public String getFullName() {
866
        return this.getDBFParameters().getFile().getAbsolutePath();
867
    }
868

    
869
    protected void resourceCloseRequest() throws ResourceException {
870
        this.dbfResource.closeRequest();
871
    }
872

    
873
    public ResourceProvider getResource() {
874
        return dbfResource;
875
    }
876
}