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

History | View | Annotate | Download (32 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.gvsig.fmap.dal.DALLocator;
40
import org.gvsig.fmap.dal.DataManager;
41
import org.gvsig.fmap.dal.DataServerExplorer;
42
import org.gvsig.fmap.dal.DataStoreNotification;
43
import org.gvsig.fmap.dal.DataTypes;
44
import org.gvsig.fmap.dal.FileHelper;
45
import org.gvsig.fmap.dal.exception.CloseException;
46
import org.gvsig.fmap.dal.exception.DataException;
47
import org.gvsig.fmap.dal.exception.FileNotFoundException;
48
import org.gvsig.fmap.dal.exception.InitializeException;
49
import org.gvsig.fmap.dal.exception.OpenException;
50
import org.gvsig.fmap.dal.exception.ReadException;
51
import org.gvsig.fmap.dal.exception.UnsupportedVersionException;
52
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
53
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
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.exception.UnknownDataTypeException;
65
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
66
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
67
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
68
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
69
import org.gvsig.fmap.dal.resource.ResourceAction;
70
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
71
import org.gvsig.fmap.dal.resource.exception.ResourceException;
72
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
73
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
74
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
75
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
76
import org.gvsig.fmap.dal.resource.file.FileResource;
77
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
78
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
79
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
80
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
81
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
82
import org.gvsig.fmap.dal.store.dbf.utils.DbaseFile;
83
import org.gvsig.metadata.MetadataLocator;
84
import org.gvsig.metadata.MetadataManager;
85
import org.gvsig.metadata.exceptions.MetadataException;
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.slf4j.Logger;
91
import org.slf4j.LoggerFactory;
92

    
93
public class DBFStoreProvider extends AbstractFeatureStoreProvider implements
94
        ResourceConsumer {
95

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

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

    
100
    public static String NAME = "DBF";
101
    public static String DESCRIPTION = "DBF file";
102
    private static final Locale ukLocale = new Locale("en", "UK");
103

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

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

    
113
    private static long lastLogTime = 0;
114

    
115
    private boolean loTengoEnUso;
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

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

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

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

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

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

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

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

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

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

    
232
        try {
233
            // TODO repasar el concepto de enUso de un recurso.
234
            loTengoEnUso = true;
235
            final FeatureStore store
236
                    = this.getStoreServices().getFeatureStore();
237
            resourceCloseRequest();
238
            getResource().execute(new ResourceAction() {
239

    
240
                public Object run() throws Exception {
241
                    FeatureSet set = null;
242
                    DisposableIterator iter = null;
243
                    try {
244
                        set = store.getFeatureSet();
245
                        DBFStoreParameters tmpParams
246
                                = (DBFStoreParameters) getDBFParameters().getCopy();
247

    
248
                        File tmp_file = File.createTempFile(
249
                                "tmp_" + System.currentTimeMillis(), ".dbf");
250
                        tmp_file.deleteOnExit();
251

    
252
                        tmpParams.setDBFFile(tmp_file);
253

    
254
                        writer.begin(tmpParams, store.getDefaultFeatureType(),
255
                                set.getSize());
256

    
257
                        iter = set.fastIterator();
258
                        while (iter.hasNext()) {
259
                            Feature feature = (Feature) iter.next();
260
                            writer.append(feature);
261
                        }
262

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

    
272
                        File target_file = getDBFParameters().getDBFFile();
273
                        if (target_file.exists()) {
274
                            target_file.delete();
275
                        }
276
                        tmp_file.renameTo(target_file);
277

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

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

    
306
        this.counterNewsOIDs = -1;
307
    }
308

    
309
    protected void checkNewFieldsNameSize(Iterator ft_upd) throws PerformEditingException {
310

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

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

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

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

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

    
362

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

    
378
    protected EditableFeatureType getTheFeatureType()
379
            throws InitializeException, OpenException {
380
        try {
381
            this.open();
382
        } catch (DataException e) {
383
            throw new InitializeException(this.getProviderName(), e);
384
        }
385
        return (EditableFeatureType) getResource().execute(
386
                new ResourceAction() {
387

    
388
                    public Object run() throws Exception {
389
                        int fieldCount = -1;
390
                        fieldCount = dbfFile.getFieldCount();
391

    
392
                        EditableFeatureType fType = getStoreServices().createFeatureType(getName());
393

    
394
                        fType.setHasOID(true);
395
                        int precision;
396
                        for (int i = 0; i < fieldCount; i++) {
397
                            char fieldType = dbfFile.getFieldType(i);
398
                            EditableFeatureAttributeDescriptor attr;
399

    
400
                            if (fieldType == 'L') {
401
                                attr = fType.add(dbfFile.getFieldName(i), DataTypes.BOOLEAN);
402
                                attr.setDefaultValue(new Boolean(false));
403
                                attr.setAllowNull(false);
404

    
405
                            } else if ((fieldType == 'F') || (fieldType == 'N')) {
406
                                precision = dbfFile.getFieldDecimalLength(i);
407
                                if (precision > 0) {
408
                                    attr = fType.add(dbfFile.getFieldName(i),
409
                                            DataTypes.DOUBLE,
410
                                            dbfFile.getFieldLength(i));
411
                                    attr.setPrecision(precision);
412
                                    attr.setDefaultValue(new Double(0));
413

    
414
                                } else {
415
                                    int length = dbfFile.getFieldLength(i);
416
                                    int type = DataTypes.INT;
417
                                    if (length > 9) {
418
                                        type = DataTypes.LONG;
419
                                    }
420
                                    attr = fType.add(dbfFile.getFieldName(i),
421
                                            type,
422
                                            length);
423
                                    attr.setDefaultValue(new Integer(0));
424
                                }
425
                                attr.setAllowNull(false);
426

    
427
                            } else if (fieldType == 'C' || getDBFParameters().handleDatesAsStrings()) {
428
                                attr = fType.add(dbfFile.getFieldName(i), DataTypes.STRING);
429
                                attr.setSize(dbfFile.getFieldLength(i));
430
                                attr.setDefaultValue("");
431
                                attr.setAllowNull(false);
432

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

    
454
                        // FeatureRules rules = fType.getRules();
455
                        // rules.add(new DBFRowValidator());
456
                        return fType;
457
                    }
458
                }
459
        );
460
    }
461

    
462
    protected void loadValue(FeatureProvider featureProvider, int rowIndex,
463
            FeatureAttributeDescriptor descriptor) throws ReadException {
464

    
465
        if (descriptor.getEvaluator() != null) {
466
            // Nothing to do
467
            return;
468
        }
469

    
470
        int dbfIndex = this.dbfFile.getFieldIndex(descriptor.getName());
471

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

    
488
        String value = null;
489
        try {
490
            value = this.dbfFile.getStringFieldValue(rowIndex, dbfIndex);
491
        } catch (DataException e) {
492
            throw new ReadException(this.getName(), e);
493
        }
494
        value = value.trim();
495
        int fieldType = descriptor.getType();
496
        switch (fieldType) {
497
            case DataTypes.STRING:
498
                featureProvider.set(descriptor.getIndex(), value);
499
                break;
500

    
501
            case DataTypes.DOUBLE:
502
                try {
503
                    featureProvider.set(descriptor.getIndex(), new Double(value));
504
                } catch (NumberFormatException e) {
505
                    featureProvider.set(descriptor.getIndex(), null);
506
                }
507
                break;
508

    
509
            case DataTypes.INT:
510
                try {
511
                    featureProvider.set(descriptor.getIndex(), new Integer(value));
512
                } catch (NumberFormatException e) {
513
                    featureProvider.set(descriptor.getIndex(), null);
514
                }
515
                break;
516

    
517
            case DataTypes.FLOAT:
518
                try {
519
                    featureProvider.set(descriptor.getIndex(), new Float(value));
520
                } catch (NumberFormatException e) {
521
                    featureProvider.set(descriptor.getIndex(), null);
522
                }
523
                break;
524

    
525
            case DataTypes.LONG:
526
                try {
527
                    featureProvider.set(descriptor.getIndex(), new Long(value));
528
                } catch (NumberFormatException e) {
529
                    featureProvider.set(descriptor.getIndex(), null);
530
                }
531
                break;
532

    
533
            case DataTypes.BOOLEAN:
534
                if (value.equalsIgnoreCase("T")) {
535
                    featureProvider.set(descriptor.getIndex(), Boolean.TRUE);
536
                } else {
537
                    featureProvider.set(descriptor.getIndex(), Boolean.FALSE);
538

    
539
                }
540
                break;
541

    
542
            case DataTypes.BYTE:
543
                try {
544
                    featureProvider.set(descriptor.getIndex(), new Byte(value));
545
                } catch (NumberFormatException e) {
546
                    featureProvider.set(descriptor.getIndex(), null);
547
                }
548
                break;
549

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

    
565
            default:
566
                featureProvider
567
                        .set(descriptor.getIndex(), descriptor.getDefaultValue());
568
                break;
569
        }
570
    }
571

    
572
    private static class InvalidDateException extends ReadException {
573
        public InvalidDateException(String dateFormat, String value, String store, Throwable cause) {
574
            super(
575
                    "Can't parse date value '%(value)' with format '%(dateFormat)' in dbf '%(store)'.",
576
                    cause,
577
                    "Cant_parse_date_value_XvalueX_with_format_XdateFormatX_in_dbf_XstoreX",
578
                    0
579
            );
580
            setValue("dateFormat",dateFormat);
581
            setValue("value", value);
582
            setValue("store",store);
583
        }
584
    }
585

    
586
    /**
587
     * *
588
     * NOT supported in Alter Mode
589
     *
590
     * @param index
591
     * @return
592
     * @throws ReadException
593
     */
594
    protected FeatureProvider getFeatureProviderByIndex(long index) throws DataException {
595
        return this
596
                .getFeatureProviderByIndex(index, this.getStoreServices()
597
                        .getDefaultFeatureType());
598
    }
599

    
600
    public long getFeatureCount() throws ReadException, OpenException,
601
            ResourceNotifyChangesException {
602
        this.open();
603
        return ((Long) getResource().execute(new ResourceAction() {
604
            public Object run() throws Exception {
605
                return Long.valueOf(dbfFile.getRecordCount());
606
            }
607
        })).longValue();
608
    }
609

    
610
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
611
            throws DataException {
612
        return new DBFSetProvider(this, query, featureType);
613
    }
614

    
615
    public boolean canCreate() {
616
        return true;
617
    }
618

    
619
    public boolean canWriteGeometry(int geometryType, int geometrySubType) throws DataException {
620
        return false;
621
    }
622

    
623
    public void open() throws OpenException {
624
        if (this.dbfFile.isOpen()) {
625
            return;
626
        }
627
        try {
628
            getResource().execute(new ResourceAction() {
629
                public Object run() throws Exception {
630
                    openFile();
631
                    resourcesOpen();
632
                    return null;
633
                }
634
            });
635

    
636
        } catch (ResourceExecuteException e) {
637
            throw new OpenException(this.getProviderName(), e);
638
        }
639
    }
640

    
641
    protected void openFile() throws FileNotFoundException,
642
            UnsupportedVersionException, IOException, DataException {
643
        this.dbfFile.open();
644
    }
645

    
646
    public void close() throws CloseException {
647
        if( loTengoEnUso ) {
648
            return;
649
        }
650
        if (dbfFile == null || !this.dbfFile.isOpen()) {
651
            return;
652
        }
653
        super.close();
654

    
655
        //Cerrar recurso
656
        try {
657
            getResource().execute(new ResourceAction() {
658
                public Object run() throws Exception {
659
                    closeFile();
660
                    resourcesNotifyClose();
661
                    return null;
662
                }
663
            });
664
        } catch (ResourceExecuteException  e) {
665
            throw new CloseException(this.getProviderName(), e);
666
        }
667
    }
668

    
669
    protected void closeFile() throws CloseException {
670
        this.dbfFile.close();
671
    }
672

    
673
    @Override
674
    protected void doDispose() throws BaseException {
675
        this.close();
676
        dbfFile = null;
677
        disposeResource();
678
        super.doDispose();
679
    }
680

    
681
    protected void disposeResource() {
682
        this.dbfResource.removeConsumer(this);
683
        dbfResource = null;
684
    }
685

    
686
    public boolean closeResourceRequested(ResourceProvider resource) {
687
        try {
688
            this.close();
689
        } catch (CloseException e) {
690
            return false;
691
        }
692
        return true;
693
    }
694

    
695
    public boolean allowWrite() {
696
        File file;
697
        try {
698
            file = ((File) this.dbfResource.get());
699
        } catch (AccessResourceException e) {
700
            return false;
701
        }
702
        return file.canWrite();
703
    }
704

    
705
    public void refresh() throws OpenException {
706
        try {
707
            this.close();
708
        } catch (CloseException e) {
709
            throw new OpenException(this.getProviderName(), e);
710
        }
711
        this.open();
712
        try {
713
            this.initFeatureType();
714
        } catch (InitializeException e) {
715
            throw new OpenException(this.getProviderName(), e);
716
        }
717
    }
718

    
719
    /**
720
     *
721
     * @param index
722
     * @param featureType
723
     * @return
724
     * @throws ReadException
725
     */
726
    protected FeatureProvider getFeatureProviderByIndex(long index,
727
            FeatureType featureType) throws DataException {
728
        FeatureProvider featureProvider = this.createFeatureProvider(featureType);
729
        featureProvider.setOID(new Long(index));
730
        return featureProvider;
731
    }
732

    
733
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
734
            long index, FeatureType featureType) throws DataException {
735
        featureProvider.setOID(new Long(index));
736
    }
737

    
738
    /**
739
     *
740
     * @param featureProvider
741
     * @throws DataException
742
     */
743
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
744
            throws DataException {
745

    
746
        long index = ((Long) featureProvider.getOID()).longValue();
747
        int rec_count = this.dbfFile.getRecordCount();
748

    
749
        if (index >= rec_count) {
750

    
751
            ReadException rex = new ReadException(this.getName(),
752
                    new ArrayIndexOutOfBoundsException(
753
                            "Index of requested feature ("
754
                            + index + ") is >= record count (" + rec_count + ")"));
755

    
756
            LOG.info("Error while loading feature. ", rex);
757
            throw rex;
758
        }
759

    
760
        Iterator iterator = featureProvider.getType().iterator();
761
        while (iterator.hasNext()) {
762
            FeatureAttributeDescriptor descriptor
763
                    = (FeatureAttributeDescriptor) iterator.next();
764
            this.loadValue(featureProvider, (int) index, descriptor);
765
        }
766
    }
767

    
768
    public int getOIDType() {
769
        return DataTypes.LONG;
770
    }
771

    
772
    public Object createNewOID() {
773
        if (this.counterNewsOIDs < 0) {
774
            try {
775
                this.counterNewsOIDs = this.getFeatureCount();
776
            } catch (DataException e) {
777
                e.printStackTrace();
778
            }
779

    
780
        } else {
781
            this.counterNewsOIDs++;
782
        }
783
        return new Long(counterNewsOIDs);
784
    }
785

    
786
    public boolean supportsAppendMode() {
787
        return true;
788
    }
789

    
790
    public void append(final FeatureProvider featureProvider)
791
            throws DataException {
792
        getResource().execute(new ResourceAction() {
793
            public Object run() throws Exception {
794
                writer.append(getStoreServices().createFeature(featureProvider));
795
                return null;
796
            }
797
        });
798
    }
799

    
800
    public void beginAppend() throws DataException {
801
        this.close();
802
        getResource().execute(new ResourceAction() {
803
            public Object run() throws Exception {
804
                writer.begin(getDBFParameters(),
805
                        getStoreServices().getDefaultFeatureType(),
806
                        getStoreServices().getFeatureStore().getFeatureCount());
807
                return null;
808
            }
809
        });
810
    }
811

    
812
    public void endAppend() throws DataException {
813
        getResource().execute(new ResourceAction() {
814
            public Object run() throws Exception {
815
                writer.end();
816
                resourcesNotifyChanges();
817
                counterNewsOIDs = -1;
818
                return null;
819
            }
820
        });
821
    }
822

    
823
    /*
824
     * (non-Javadoc)
825
     *
826
     * @see
827
     * org.gvsig.fmap.dal.resource.spi.ResourceConsumer#resourceChanged(org.
828
     * gvsig.fmap.dal.resource.spi.ResourceProvider)
829
     */
830
    public void resourceChanged(ResourceProvider resource) {
831
        if (this.getStoreServices()!=null){
832
            this.getStoreServices().notifyChange(
833
                    DataStoreNotification.RESOURCE_CHANGED,
834
                    resource);
835
        }
836
    }
837

    
838
    /**
839
     *
840
     * @throws ResourceNotifyChangesException
841
     */
842
    protected void resourcesNotifyChanges()
843
            throws ResourceNotifyChangesException {
844
        this.dbfResource.notifyChanges();
845
    }
846

    
847
    /**
848
     * @throws ResourceNotifyCloseException
849
     *
850
     */
851
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
852
        this.dbfResource.notifyClose();
853
    }
854

    
855
    /**
856
     * @throws ResourceNotifyOpenException
857
     *
858
     */
859
    protected void resourcesOpen() throws ResourceNotifyOpenException {
860
        this.dbfResource.notifyOpen();
861
    }
862

    
863
    public Object getSourceId() {
864
        return this.getDBFParameters().getFile();
865
    }
866

    
867
    public String getName() {
868
        String name = this.getDBFParameters().getFile().getName();
869
        int n = name.lastIndexOf(".");
870
        if (n < 1) {
871
            return name;
872
        }
873
        return name.substring(0, n);
874
    }
875

    
876
    public String getFullName() {
877
        return this.getDBFParameters().getFile().getAbsolutePath();
878
    }
879

    
880
    protected void resourceCloseRequest() throws ResourceException {
881
        this.dbfResource.closeRequest();
882
    }
883

    
884
    public ResourceProvider getResource() {
885
        return dbfResource;
886
    }
887
}