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

History | View | Annotate | Download (34.1 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.MessageFormat;
30
import java.text.ParseException;
31
import java.text.SimpleDateFormat;
32
import java.util.ArrayList;
33
import java.util.Date;
34
import java.util.Iterator;
35
import java.util.List;
36
import java.util.Locale;
37
import java.util.logging.Level;
38

    
39
import org.apache.commons.io.FileUtils;
40
import org.apache.commons.lang3.StringUtils;
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.resource.ResourceAction;
73
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
74
import org.gvsig.fmap.dal.resource.exception.ResourceException;
75
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
76
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
77
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
78
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
79
import org.gvsig.fmap.dal.resource.file.FileResource;
80
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
81
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
82
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
83
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
84
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
85
import org.gvsig.fmap.dal.store.dbf.utils.DbaseFile;
86
import org.gvsig.metadata.MetadataLocator;
87
import org.gvsig.metadata.MetadataManager;
88
import org.gvsig.metadata.exceptions.MetadataException;
89
import org.gvsig.tools.dataTypes.CoercionException;
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
import org.slf4j.Logger;
96
import org.slf4j.LoggerFactory;
97

    
98
public class DBFStoreProvider extends AbstractFeatureStoreProvider implements
99
        ResourceConsumer {
100

    
101
    private static final Logger LOG = LoggerFactory.getLogger(DBFStoreProvider.class);
102

    
103
    public static final int MAX_FIELD_NAME_LENGTH = DbaseFile.MAX_FIELD_NAME_LENGTH;
104

    
105
    public static String NAME = "DBF";
106
    public static String DESCRIPTION = "DBF file";
107
    private static final Locale ukLocale = new Locale("en", "UK");
108

    
109
    public static final String METADATA_DEFINITION_NAME = NAME;
110
    private static final String METADATA_ENCODING = "Encoding";
111
    private static final String METADATA_CODEPAGE = "CodePage";
112

    
113
    private DbaseFile dbfFile = null;
114
    private ResourceProvider dbfResource;
115
    private long counterNewsOIDs = -1;
116
    private DBFFeatureWriter writer;
117

    
118
    private static long lastLogTime = 0;
119

    
120
    private boolean loTengoEnUso;
121

    
122
    private boolean allowDuplicatedFieldNames;
123

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

    
135
    public DBFStoreProvider(DBFStoreParameters params,
136
            DataStoreProviderServices storeServices)
137
            throws InitializeException {
138
        super(
139
                params,
140
                storeServices,
141
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
142
        );
143
        this.init(params, storeServices);
144
    }
145

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

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

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

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

    
170
        this.initFeatureType();
171

    
172
    }
173

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

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

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

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

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

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

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

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

    
229
    protected FeatureProvider internalGetFeatureProviderByReference(
230
            FeatureReferenceProviderServices reference, FeatureType featureType)
231
            throws DataException {
232
        return this.getFeatureProviderByIndex(
233
                ((Number) reference.getOID()).longValue(), featureType);
234
    }
235

    
236
    public void performChanges(Iterator deleteds, Iterator inserteds,
237
            Iterator updateds, Iterator originalFeatureTypesUpdated)
238
            throws PerformEditingException {
239

    
240
        /*
241
         * This will throw an exception if there are new fields
242
         * with names too long
243
         */
244
        checkNewFieldsNameSize(originalFeatureTypesUpdated);
245

    
246
        try {
247
            // TODO repasar el concepto de enUso de un recurso.
248
            loTengoEnUso = true;
249
            final FeatureStore store
250
                    = this.getStoreServices().getFeatureStore();
251
            resourceCloseRequest();
252
            getResource().execute(new ResourceAction() {
253

    
254
                public Object run() throws Exception {
255
                    FeatureSet set = null;
256
                    DisposableIterator iter = null;
257
                    try {
258
                        set = store.getFeatureSet();
259
                        DBFStoreParameters tmpParams
260
                                = (DBFStoreParameters) getDBFParameters().getCopy();
261

    
262
                        File tmp_file = File.createTempFile(
263
                                "tmp_" + System.currentTimeMillis(), ".dbf");
264
                        tmp_file.deleteOnExit();
265

    
266
                        tmpParams.setDBFFile(tmp_file);
267

    
268
                        writer.begin(tmpParams, store.getDefaultFeatureType(),
269
                                set.getSize());
270

    
271
                        iter = set.fastIterator();
272
                        while (iter.hasNext()) {
273
                            Feature feature = (Feature) iter.next();
274
                            writer.append(feature);
275
                        }
276

    
277
                        writer.end();
278
                        loTengoEnUso = false;
279
                        try {
280
                            close();
281
                        } catch (CloseException e1) {
282
                            throw new PerformEditingException(getProviderName(), e1);
283
                        }
284
                        getDBFParameters().getDBFFile().delete();
285

    
286
                        File target_file = getDBFParameters().getDBFFile();
287
                        if (target_file.exists()) {
288
                            target_file.delete();
289
                        }
290
                        tmp_file.renameTo(target_file);
291

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

    
302
                        resourcesNotifyChanges();
303
                        initFeatureType();
304
                    } finally {
305
                        loTengoEnUso = false;
306
                        if (set != null) {
307
                            set.dispose();
308
                        }
309
                        if (iter != null) {
310
                            iter.dispose();
311
                        }
312
                    }
313
                    return null;
314
                }
315
            });
316
        } catch (ResourceExecuteException | ResourceException e) {
317
            throw new PerformEditingException(this.getProviderName(), e);
318
        }
319

    
320
        this.counterNewsOIDs = -1;
321
    }
322

    
323
    protected void checkNewFieldsNameSize(Iterator ft_upd) throws PerformEditingException {
324

    
325
        String long_fields = getNewFieldsWithNameTooLong(ft_upd);
326
        if (long_fields != null) {
327
            AttributeNameException ane = new AttributeNameTooLongException(
328
                    long_fields,
329
                    getProviderName(),
330
                    MAX_FIELD_NAME_LENGTH);
331
            throw new PerformEditingException(getProviderName(), ane);
332
        }
333
    }
334

    
335
    /**
336
     * Returns null or a string which is a comma-separated list
337
     *
338
     * @param ft_updated
339
     * @return
340
     */
341
    protected String getNewFieldsWithNameTooLong(Iterator ft_updated) {
342

    
343
        String resp = "";
344
        FeatureTypeChanged item = null;
345
        FeatureType ft = null;
346
        FeatureAttributeDescriptor[] atts = null;
347
        while (ft_updated.hasNext()) {
348
            item = (FeatureTypeChanged) ft_updated.next();
349
            ft = item.getTarget();
350
            atts = ft.getAttributeDescriptors();
351
            for (int i = 0; i < atts.length; i++) {
352
                if (atts[i].getName().length() > MAX_FIELD_NAME_LENGTH) {
353
                    if (resp.length() == 0) {
354
                        resp = atts[i].getName();
355
                    } else {
356
                        resp = resp + ", " + atts[i].getName();
357
                    }
358
                }
359
            }
360
        }
361

    
362
        if (resp.length() == 0) {
363
            return null;
364
        } else {
365
            return "(" + resp + ")";
366
        }
367
    }
368
    /*
369
     * ==================================================
370
     */
371

    
372
    public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
373
        return new DBFFeatureProvider(this, type);
374
    }
375

    
376

    
377
    /*
378
     * ===================================================
379
     */
380
    protected void initFeatureType() throws InitializeException {
381
        try {
382
            FeatureType defaultType
383
                    = this.getTheFeatureType().getNotEditableCopy();
384
            List types = new ArrayList(1);
385
            types.add(defaultType);
386
            this.getStoreServices().setFeatureTypes(types, defaultType);
387
        } catch (OpenException e) {
388
            throw new InitializeException(getResource().toString(), e);
389
        }
390
    }
391

    
392
    public class DuplicatedFieldNameException extends ReadException {
393

    
394
        /**
395
         *
396
         */
397
        private static final long serialVersionUID = -1671651605329756160L;
398
        private final static String MESSAGE_FORMAT = "Duplicated field name '%(fieldName)'.\nCheck 'Allow duplicated field names' in layer properties in add layer dialog. The layer will become read only.";
399
        private final static String MESSAGE_KEY = "_DuplicatedFieldNameException";
400

    
401
        public DuplicatedFieldNameException(String fieldName) {
402
            super(MESSAGE_FORMAT, null, MESSAGE_KEY, serialVersionUID);
403
            setValue("fieldName", fieldName);
404
        }
405
    }
406

    
407
//
408
//    private String getUniqueFieldName(String fieldName, EditableFeatureType fType) {
409
//
410
//        int index = 1;
411
//        String tempFieldName = fieldName;
412
//        while(fType.get(tempFieldName)!=null && index<1000){
413
//            index++;
414
//            String sufix = String.valueOf(index);
415
//            tempFieldName = tempFieldName.substring(0, DbaseFile.MAX_FIELD_NAME_LENGTH-sufix.length())+sufix;
416
//        }
417
//        if(index>=1000){
418
//            throw new RuntimeException("Can't fix duplicated name for field '"+fieldName+"'.");
419
//        }
420
//        return tempFieldName;
421
//    }
422

    
423
    protected EditableFeatureType getTheFeatureType()
424
            throws InitializeException, OpenException {
425
        try {
426
            this.open();
427
        } catch (DataException e) {
428
            throw new InitializeException(this.getProviderName(), e);
429
        }
430
        return (EditableFeatureType) getResource().execute(
431
                new ResourceAction() {
432

    
433
                    public Object run() throws Exception {
434
                        int fieldCount = -1;
435
                        fieldCount = dbfFile.getFieldCount();
436

    
437
                        EditableFeatureType fType = getStoreServices().createFeatureType(getName());
438

    
439
                        fType.setHasOID(true);
440
                        int precision;
441
                        for (int i = 0; i < fieldCount; i++) {
442
                            char fieldType = dbfFile.getFieldType(i);
443
                            EditableFeatureAttributeDescriptor attr;
444

    
445
                            String fieldName = dbfFile.getFieldName(i);
446
                            if(fType.get(fieldName)!=null){
447
                                throw new DuplicatedFieldNameException(fieldName);
448
                            }
449

    
450
                            if (fieldType == 'L') {
451
                                attr = fType.add(fieldName, DataTypes.BOOLEAN);
452
                                attr.setDefaultValue(new Boolean(false));
453
                                attr.setAllowNull(false);
454

    
455
                            } else if ((fieldType == 'F') || (fieldType == 'N')) {
456
                                precision = dbfFile.getFieldDecimalLength(i);
457
                                if (precision > 0) {
458
                                    attr = fType.add(fieldName,
459
                                            DataTypes.DOUBLE,
460
                                            dbfFile.getFieldLength(i));
461
                                    attr.setPrecision(precision);
462
                                    attr.setDefaultValue(new Double(0));
463

    
464
                                } else {
465
                                    int length = dbfFile.getFieldLength(i);
466
                                    int type = DataTypes.INT;
467
                                    if (length > 9) {
468
                                        type = DataTypes.LONG;
469
                                    }
470
                                    attr = fType.add(fieldName,
471
                                            type,
472
                                            length);
473
                                    attr.setDefaultValue(new Integer(0));
474
                                }
475
                                attr.setAllowNull(false);
476

    
477
                            } else if (fieldType == 'C' || getDBFParameters().handleDatesAsStrings()) {
478
                                attr = fType.add(fieldName, DataTypes.STRING);
479
                                attr.setSize(dbfFile.getFieldLength(i));
480
                                attr.setDefaultValue("");
481
                                attr.setAllowNull(false);
482

    
483
                            } else if (fieldType == 'D') {
484
                                attr = fType.add(fieldName, DataTypes.DATE);
485
                                attr.setDefaultValue(new Date(0)); // def value 1-1-1970
486
                                attr.setAllowNull(true);
487
                                String sfmt = getDBFParameters().getDateFormat();
488
                                if (!StringUtils.isBlank(sfmt)) {
489
                                    try {
490
                                        SimpleDateFormat datefmt = new SimpleDateFormat(sfmt, getDBFParameters().getLocale());
491
                                        attr.setDateFormat(datefmt);
492
                                    } catch (Exception ex) {
493
                                        LOG.warn("Invalid date format ("+sfmt+") specified in DBF parameters.",ex);
494
                                    }
495
                                }
496
                            } else {
497
                                throw new InitializeException(getProviderName(),
498
                                        new UnknownDataTypeException(
499
                                            fieldName, ""
500
                                                + fieldType, getProviderName()));
501
                            }
502
                        }
503

    
504
                        // FeatureRules rules = fType.getRules();
505
                        // rules.add(new DBFRowValidator());
506
                        return fType;
507
                    }
508

    
509
                }
510
        );
511
    }
512

    
513
    protected void loadValue(FeatureProvider featureProvider, long rowIndex,
514
            FeatureAttributeDescriptor descriptor) throws ReadException {
515

    
516
        if (descriptor.getEvaluator() != null) {
517
            // Nothing to do
518
            return;
519
        }
520

    
521
        int dbfIndex = this.dbfFile.getFieldIndex(descriptor.getName());
522

    
523
        if (dbfIndex < 0) {
524
            // Someone asked to load a field
525
            // which does not exist in the DBF file. This can happen
526
            // in editing process when a field has been added
527
            // in the current editing session, so we simply do nothing.
528
            // The expansion manager is expected to manage those new fields
529
            // and their values.
530
            long curr_time = System.currentTimeMillis();
531
            // This ensures not more than one log every 2 seconds
532
            if (curr_time - lastLogTime > 2000) {
533
                LOG.info("Warning: The requested field does not exist in the DBF file. Assumed it's a new field in editing mode.");
534
                lastLogTime = curr_time;
535
            }
536
            return;
537
        }
538

    
539
        String value = null;
540
        try {
541
            value = this.dbfFile.getStringFieldValue(rowIndex, dbfIndex);
542
        } catch (DataException e) {
543
            throw new ReadException(this.getName(), e);
544
        }
545
        value = value.trim();
546
        int fieldType = descriptor.getType();
547
        switch (fieldType) {
548
            case DataTypes.STRING:
549
                featureProvider.set(descriptor.getIndex(), value);
550
                break;
551

    
552
            case DataTypes.DOUBLE:
553
                try {
554
                    featureProvider.set(descriptor.getIndex(), new Double(value));
555
                } catch (NumberFormatException e) {
556
                    featureProvider.set(descriptor.getIndex(), null);
557
                }
558
                break;
559

    
560
            case DataTypes.INT:
561
                try {
562
                    featureProvider.set(descriptor.getIndex(), new Integer(value));
563
                } catch (NumberFormatException e) {
564
                    featureProvider.set(descriptor.getIndex(), null);
565
                }
566
                break;
567

    
568
            case DataTypes.FLOAT:
569
                try {
570
                    featureProvider.set(descriptor.getIndex(), new Float(value));
571
                } catch (NumberFormatException e) {
572
                    featureProvider.set(descriptor.getIndex(), null);
573
                }
574
                break;
575

    
576
            case DataTypes.LONG:
577
                try {
578
                    featureProvider.set(descriptor.getIndex(), new Long(value));
579
                } catch (NumberFormatException e) {
580
                    featureProvider.set(descriptor.getIndex(), null);
581
                }
582
                break;
583

    
584
            case DataTypes.BOOLEAN:
585
                if (value.equalsIgnoreCase("T")) {
586
                    featureProvider.set(descriptor.getIndex(), Boolean.TRUE);
587
                } else {
588
                    featureProvider.set(descriptor.getIndex(), Boolean.FALSE);
589

    
590
                }
591
                break;
592

    
593
            case DataTypes.BYTE:
594
                try {
595
                    featureProvider.set(descriptor.getIndex(), new Byte(value));
596
                } catch (NumberFormatException e) {
597
                    featureProvider.set(descriptor.getIndex(), null);
598
                }
599
                break;
600

    
601
            case DataTypes.DATE:
602
                if (value.equals("")) {
603
                    value = null;
604
                    return;
605
                }
606
                Date dat = null;
607
                DateFormat df = new SimpleDateFormat("yyyyMMdd");
608
                try {
609
                    dat = df.parse(value);
610
                } catch (ParseException e) {
611
                    throw new InvalidDateException(df.toString(), value, this.getProviderName(), e);
612
                }
613
                featureProvider.set(descriptor.getIndex(), dat);
614
                break;
615

    
616
            default: {
617
                    Object v;
618
                    try {
619
                        v = descriptor.getDataType().coerce(value);
620
                    } catch (CoercionException ex) {
621
                        v = descriptor.getDefaultValue();
622
                    }
623
                    featureProvider.set(descriptor.getIndex(), v);
624
                }
625
                break;
626
        }
627
    }
628

    
629
    private static class InvalidDateException extends ReadException {
630
        public InvalidDateException(String dateFormat, String value, String store, Throwable cause) {
631
            super(
632
                    "Can't parse date value '%(value)' with format '%(dateFormat)' in dbf '%(store)'.",
633
                    cause,
634
                    "Cant_parse_date_value_XvalueX_with_format_XdateFormatX_in_dbf_XstoreX",
635
                    0
636
            );
637
            setValue("dateFormat",dateFormat);
638
            setValue("value", value);
639
            setValue("store",store);
640
        }
641
    }
642

    
643
    /**
644
     * *
645
     * NOT supported in Alter Mode
646
     *
647
     * @param index
648
     * @return
649
     * @throws ReadException
650
     */
651
    protected FeatureProvider getFeatureProviderByIndex(long index) throws DataException {
652
        return this
653
                .getFeatureProviderByIndex(index, this.getStoreServices()
654
                        .getDefaultFeatureType());
655
    }
656

    
657
    public long getFeatureCount() throws ReadException, OpenException,
658
            ResourceNotifyChangesException {
659
        this.open();
660
        return ((Long) getResource().execute(new ResourceAction() {
661
            public Object run() throws Exception {
662
                return Long.valueOf(dbfFile.getRecordCount());
663
            }
664
        })).longValue();
665
    }
666

    
667
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
668
            throws DataException {
669
        return new DBFSetProvider(this, query, featureType);
670
    }
671

    
672
    public boolean canCreate() {
673
        return true;
674
    }
675

    
676
    public boolean canWriteGeometry(int geometryType, int geometrySubType) throws DataException {
677
        return false;
678
    }
679

    
680
    public void open() throws OpenException {
681
        if (this.dbfFile.isOpen()) {
682
            return;
683
        }
684
        try {
685
            getResource().execute(new ResourceAction() {
686
                public Object run() throws Exception {
687
                    openFile();
688
                    resourcesOpen();
689
                    return null;
690
                }
691
            });
692

    
693
        } catch (ResourceExecuteException e) {
694
            throw new OpenException(this.getProviderName(), e);
695
        }
696
    }
697

    
698
    protected void openFile() throws FileNotFoundException,
699
            UnsupportedVersionException, IOException, DataException {
700
        this.dbfFile.open();
701
        // necessary when editing the file
702
        this.getDBFParameters().setEffectiveEncoding(this.dbfFile.getCharsetName());
703
    }
704

    
705
    public void close() throws CloseException {
706
        if( loTengoEnUso ) {
707
            return;
708
        }
709
        if (dbfFile == null || !this.dbfFile.isOpen()) {
710
            return;
711
        }
712
        super.close();
713

    
714
        //Cerrar recurso
715
        try {
716
            getResource().execute(new ResourceAction() {
717
                public Object run() throws Exception {
718
                    closeFile();
719
                    resourcesNotifyClose();
720
                    return null;
721
                }
722
            });
723
        } catch (ResourceExecuteException  e) {
724
            throw new CloseException(this.getProviderName(), e);
725
        }
726
    }
727

    
728
    protected void closeFile() throws CloseException {
729
        this.dbfFile.close();
730
    }
731

    
732
    @Override
733
    protected void doDispose() throws BaseException {
734
        this.close();
735
        dbfFile = null;
736
        disposeResource();
737
        super.doDispose();
738
    }
739

    
740
    protected void disposeResource() {
741
        this.dbfResource.removeConsumer(this);
742
        dbfResource = null;
743
    }
744

    
745
    public boolean closeResourceRequested(ResourceProvider resource) {
746
        try {
747
            this.close();
748
        } catch (CloseException e) {
749
            return false;
750
        }
751
        return true;
752
    }
753

    
754
    public boolean allowWrite() {
755
        if(allowDuplicatedFieldNames){
756
            return false;
757
        }
758
        return this.dbfFile.isWritable();
759
    }
760

    
761
    public void refresh() throws OpenException {
762
        try {
763
            this.close();
764
        } catch (CloseException e) {
765
            throw new OpenException(this.getProviderName(), e);
766
        }
767
        this.open();
768
        try {
769
            this.initFeatureType();
770
        } catch (InitializeException e) {
771
            throw new OpenException(this.getProviderName(), e);
772
        }
773
    }
774

    
775
    /**
776
     *
777
     * @param index
778
     * @param featureType
779
     * @return
780
     * @throws ReadException
781
     */
782
    protected FeatureProvider getFeatureProviderByIndex(long index,
783
            FeatureType featureType) throws DataException {
784
        FeatureProvider featureProvider = this.createFeatureProvider(featureType);
785
        featureProvider.setOID(new Long(index));
786
        return featureProvider;
787
    }
788

    
789
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
790
            long index, FeatureType featureType) throws DataException {
791
        featureProvider.setOID(new Long(index));
792
    }
793

    
794
    /**
795
     *
796
     * @param featureProvider
797
     * @throws DataException
798
     */
799
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
800
            throws DataException {
801

    
802
        long index = ((Long) featureProvider.getOID());
803
        int rec_count = this.dbfFile.getRecordCount();
804

    
805
        if (index >= rec_count) {
806

    
807
            ReadException rex = new ReadException(this.getName(),
808
                    new ArrayIndexOutOfBoundsException(
809
                            "Index of requested feature ("
810
                            + index + ") is >= record count (" + rec_count + ")"));
811

    
812
            LOG.info("Error while loading feature. ", rex);
813
            throw rex;
814
        }
815

    
816
        Iterator iterator = featureProvider.getType().iterator();
817
        while (iterator.hasNext()) {
818
            FeatureAttributeDescriptor descriptor
819
                    = (FeatureAttributeDescriptor) iterator.next();
820
            this.loadValue(featureProvider, index, descriptor);
821
        }
822
    }
823

    
824
    public int getOIDType() {
825
        return DataTypes.LONG;
826
    }
827

    
828
    public Object createNewOID() {
829
        if (this.counterNewsOIDs < 0) {
830
            try {
831
                this.counterNewsOIDs = this.getFeatureCount();
832
            } catch (DataException e) {
833
                e.printStackTrace();
834
            }
835

    
836
        } else {
837
            this.counterNewsOIDs++;
838
        }
839
        return new Long(counterNewsOIDs);
840
    }
841

    
842
    public boolean supportsAppendMode() {
843
        return true;
844
    }
845

    
846
    public void append(final FeatureProvider featureProvider)
847
            throws DataException {
848
        getResource().execute(new ResourceAction() {
849
            public Object run() throws Exception {
850
                writer.append(getStoreServices().createFeature(featureProvider));
851
                return null;
852
            }
853
        });
854
    }
855

    
856
    public void beginAppend() throws DataException {
857
        this.close();
858
        getResource().execute(new ResourceAction() {
859
            public Object run() throws Exception {
860
                writer.begin(getDBFParameters(),
861
                        getStoreServices().getDefaultFeatureType(),
862
                        getStoreServices().getFeatureStore().getFeatureCount());
863
                return null;
864
            }
865
        });
866
    }
867

    
868
    public void endAppend() throws DataException {
869
        getResource().execute(new ResourceAction() {
870
            public Object run() throws Exception {
871
                writer.end();
872
                resourcesNotifyChanges();
873
                counterNewsOIDs = -1;
874
                return null;
875
            }
876
        });
877
    }
878

    
879
    /*
880
     * (non-Javadoc)
881
     *
882
     * @see
883
     * org.gvsig.fmap.dal.resource.spi.ResourceConsumer#resourceChanged(org.
884
     * gvsig.fmap.dal.resource.spi.ResourceProvider)
885
     */
886
    public void resourceChanged(ResourceProvider resource) {
887
        if (this.getStoreServices()!=null){
888
            this.getStoreServices().notifyChange(
889
                    DataStoreNotification.RESOURCE_CHANGED,
890
                    resource);
891
        }
892
    }
893

    
894
    /**
895
     *
896
     * @throws ResourceNotifyChangesException
897
     */
898
    protected void resourcesNotifyChanges()
899
            throws ResourceNotifyChangesException {
900
        this.dbfResource.notifyChanges();
901
    }
902

    
903
    /**
904
     * @throws ResourceNotifyCloseException
905
     *
906
     */
907
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
908
        this.dbfResource.notifyClose();
909
    }
910

    
911
    /**
912
     * @throws ResourceNotifyOpenException
913
     *
914
     */
915
    protected void resourcesOpen() throws ResourceNotifyOpenException {
916
        this.dbfResource.notifyOpen();
917
    }
918

    
919
    public Object getSourceId() {
920
        return this.getDBFParameters().getFile();
921
    }
922

    
923
    public String getName() {
924
        String name = this.getDBFParameters().getFile().getName();
925
        int n = name.lastIndexOf(".");
926
        if (n < 1) {
927
            return name;
928
        }
929
        return name.substring(0, n);
930
    }
931

    
932
    public String getFullName() {
933
        return this.getDBFParameters().getFile().getAbsolutePath();
934
    }
935

    
936
    protected void resourceCloseRequest() throws ResourceException {
937
        this.dbfResource.closeRequest();
938
    }
939

    
940
    public ResourceProvider getResource() {
941
        return dbfResource;
942
    }
943

    
944
}