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

History | View | Annotate | Download (31.3 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.dal.store.dbf;
24

    
25
import java.io.File;
26
import java.io.IOException;
27
import java.math.BigDecimal;
28
import java.nio.charset.Charset;
29
import java.util.ArrayList;
30
import java.util.Date;
31
import java.util.Iterator;
32
import java.util.List;
33
import java.util.Locale;
34
import org.apache.commons.io.FileUtils;
35
import org.apache.commons.lang3.mutable.MutableInt;
36
import org.gvsig.fmap.dal.DALLocator;
37
import org.gvsig.fmap.dal.DataManager;
38
import org.gvsig.fmap.dal.DataServerExplorer;
39
import org.gvsig.fmap.dal.DataStore;
40
import org.gvsig.fmap.dal.DataStoreNotification;
41
import org.gvsig.fmap.dal.DataTypes;
42
import org.gvsig.fmap.dal.FileHelper;
43
import org.gvsig.fmap.dal.exception.CloseException;
44
import org.gvsig.fmap.dal.exception.DataException;
45
import org.gvsig.fmap.dal.exception.FileNotFoundException;
46
import org.gvsig.fmap.dal.exception.InitializeException;
47
import org.gvsig.fmap.dal.exception.OpenException;
48
import org.gvsig.fmap.dal.exception.ReadException;
49
import org.gvsig.fmap.dal.exception.UnsupportedVersionException;
50
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
51
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
52
import org.gvsig.fmap.dal.feature.EditableFeatureType;
53
import org.gvsig.fmap.dal.feature.Feature;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
55
import org.gvsig.fmap.dal.feature.FeatureQuery;
56
import org.gvsig.fmap.dal.feature.FeatureSet;
57
import org.gvsig.fmap.dal.feature.FeatureStore;
58
import org.gvsig.fmap.dal.feature.FeatureType;
59
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
60
import org.gvsig.fmap.dal.feature.exception.AttributeNameException;
61
import org.gvsig.fmap.dal.feature.exception.AttributeNameTooLongException;
62
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
63
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
64
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
65
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
66
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
67
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
68
import org.gvsig.fmap.dal.resource.ResourceAction;
69
import org.gvsig.fmap.dal.resource.exception.ResourceException;
70
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
71
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
72
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
73
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
74
import org.gvsig.fmap.dal.resource.file.FileResource;
75
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
76
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
77
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
78
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
79
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
80
import org.gvsig.fmap.dal.store.dbf.utils.DbaseFile;
81
import org.gvsig.fmap.dal.store.dbf.utils.FieldFormatter;
82
import org.gvsig.metadata.MetadataLocator;
83
import org.gvsig.metadata.MetadataManager;
84
import org.gvsig.metadata.exceptions.MetadataException;
85
import org.gvsig.tools.dataTypes.CoercionContext;
86
import org.gvsig.tools.dataTypes.CoercionContextDecimal;
87
import org.gvsig.tools.dataTypes.CoercionException;
88
import org.gvsig.tools.dispose.DisposableIterator;
89
import org.gvsig.tools.dynobject.DynObject;
90
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
91
import org.gvsig.tools.exception.BaseException;
92
import org.gvsig.tools.logger.FilteredLogger;
93
import org.gvsig.tools.math.BigDecimalUtils;
94
import org.slf4j.Logger;
95
import org.slf4j.LoggerFactory;
96
import sun.security.ec.point.ProjectivePoint;
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 final String NAME = DataStore.DBASE_PROVIDER_NAME;
106
    public static final String DESCRIPTION = "DBF file";
107

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

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

    
117
    private boolean loTengoEnUso;
118

    
119
    private boolean allowDuplicatedFieldNames;
120
    private FilteredLogger logger;
121
    
122
    protected EditableFeatureType featureType;
123

    
124

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

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

    
146
    protected DBFStoreProvider(DBFStoreParameters params,
147
            DataStoreProviderServices storeServices, DynObject metadata)
148
            throws InitializeException {
149
        super(params, storeServices, metadata);
150
        this.logger = new FilteredLogger(LOG, "DBFStoreProvider", -1);
151
        this.logger.setInterval(2000L);
152
        this.init(params, storeServices);
153
    }
154

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

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

    
170
        writer = new DBFFeatureWriter(this.getProviderName());
171

    
172
        this.initFeatureType();
173

    
174
    }
175

    
176
    @Override
177
    public Object getDynValue(String name) throws DynFieldNotFoundException {
178
        try {
179
            this.open();
180
        } catch (OpenException e) {
181
            throw new RuntimeException(e);
182
        }
183

    
184
        if (METADATA_ENCODING.equalsIgnoreCase(name)) {
185
            return this.dbfFile.getOriginalCharset();
186
        } else if (METADATA_CODEPAGE.equalsIgnoreCase(name)) {
187
            return this.dbfFile.getCodePageInt();
188
        }
189
        return super.getDynValue(name);
190
    }
191

    
192
    protected void initResource(DBFStoreParameters params,
193
            DataStoreProviderServices storeServices) throws InitializeException {
194

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

    
202
    protected void initResource(ResourceProvider resource,
203
        DataStoreProviderServices storeServices){
204
        dbfResource = resource;
205
        dbfResource.addConsumer(this);
206
    }
207

    
208
    @Override
209
    public String getProviderName() {
210
        return NAME;
211
    }
212

    
213
    protected DBFStoreParameters getDBFParameters() {
214
        return (DBFStoreParameters) super.getParameters();
215
    }
216

    
217
    @Override
218
    public DataServerExplorer getExplorer() throws ReadException {
219
        DataManager manager = DALLocator.getDataManager();
220
        FilesystemServerExplorerParameters params;
221
        try {
222
            params = (FilesystemServerExplorerParameters) manager
223
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
224
            params.setRoot(this.getDBFParameters().getDBFFile().getParent());
225
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
226
        } catch (DataException | ValidateDataParametersException e) {
227
            throw new ReadException(this.getName(), e);
228
        }
229
    }
230

    
231
    @Override
232
    protected FeatureProvider internalGetFeatureProviderByReference(
233
            FeatureReferenceProviderServices reference, FeatureType featureType)
234
            throws DataException {
235
        return this.getFeatureProviderByIndex(
236
                ((Number) reference.getOID()).longValue(), featureType, null);
237
    }
238

    
239
    @Override
240
    public void performChanges(Iterator deleteds, Iterator inserteds,
241
            Iterator updateds, Iterator originalFeatureTypesUpdated)
242
            throws PerformEditingException {
243

    
244
        /*
245
         * This will throw an exception if there are new fields
246
         * with names too long
247
         */
248
        checkNewFieldsNameSize(originalFeatureTypesUpdated);
249

    
250
        try {
251
            // TODO repasar el concepto de enUso de un recurso.
252
            loTengoEnUso = true;
253
            final FeatureStore theStore = this.getStoreServices().getFeatureStore();
254
            resourceCloseRequest();
255
            getResource().execute(new ResourceAction() {
256

    
257
                public Object run() throws Exception {
258
                    FeatureSet set = null;
259
                    DisposableIterator iter = null;
260
                    try {
261
                        set = theStore.getFeatureSet();
262
                        DBFStoreParameters tmpParams
263
                                = (DBFStoreParameters) getDBFParameters().getCopy();
264

    
265
                        File tmp_file = File.createTempFile(
266
                                "tmp_" + System.currentTimeMillis(), ".dbf");
267
                        tmp_file.deleteOnExit();
268

    
269
                        tmpParams.setDBFFile(tmp_file);
270

    
271
                        writer.begin(tmpParams, theStore.getDefaultFeatureType(),
272
                                set.getSize());
273

    
274
                        iter = set.fastIterator();
275
                        while (iter.hasNext()) {
276
                            Feature feature = (Feature) iter.next();
277
                            writer.append(feature);
278
                        }
279

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

    
289
                        File target_file = getDBFParameters().getDBFFile();
290
                        if (target_file.exists()) {
291
                            target_file.delete();
292
                        }
293
                        tmp_file.renameTo(target_file);
294

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

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

    
323
        this.counterNewsOIDs = -1;
324
    }
325

    
326
    protected void checkNewFieldsNameSize(Iterator ft_upd) throws PerformEditingException {
327

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

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

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

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

    
369
    @Override
370
    public FeatureProvider createFeatureProvider(FeatureType providerFeatureType) throws DataException {
371
        return new DBFFeatureProvider(this, providerFeatureType, null);
372
    }
373

    
374
    public FeatureProvider createFeatureProvider(FeatureType providerFeatureType, FeatureType storeFeatureType) throws DataException {
375
        return new DBFFeatureProvider(this, providerFeatureType, storeFeatureType);
376
    }
377

    
378
    protected void initFeatureType() throws InitializeException {
379
        this.featureType = this.getTheFeatureType();
380
        FeatureType defaultType = this.featureType.getNotEditableCopy();
381
        this.setStoreFeatureType(defaultType);
382
    }
383

    
384
    protected void setStoreFeatureType(FeatureType ftype) {
385
        FeatureStoreProviderServices store = this.getStoreServices();
386
        List<FeatureType> ftypes = new ArrayList<>();
387
        ftypes.add(ftype);
388
        store.setFeatureTypes(ftypes, ftype);
389
    }
390
        
391
    protected EditableFeatureType getTheFeatureType() throws InitializeException {
392
        try {
393
            this.open();
394
        } catch (DataException e) {
395
            throw new InitializeException(this.getProviderName(), e);
396
        }
397
        EditableFeatureType featureType = (EditableFeatureType) getResource().execute(
398
            new ResourceAction() {
399
                public Object run() throws Exception {
400
                    EditableFeatureType featureType = getStoreServices().createFeatureType(getName());
401
                    featureType.setHasOID(true);
402
                    dbfFile.getHeader().toFeatureType(
403
                            featureType,
404
                            getDBFParameters().handleDatesAsStrings()
405
                    );
406
                    return featureType;
407
                }
408
            }
409
        );
410
        return featureType;
411
    }
412
    
413
    
414
    protected void loadValue(DBFFeatureProvider featureProvider, long rowIndex,
415
            FeatureAttributeDescriptor descriptor) throws ReadException {
416

    
417
        if (descriptor.getEvaluator() != null) {
418
            // Nothing to do
419
            return;
420
        }
421

    
422
        int dbfFieldIndex = this.dbfFile.getFieldIndex(descriptor.getName());
423

    
424
        if (dbfFieldIndex < 0) {
425
            // Someone asked to load a field
426
            // which does not exist in the DBF file. This can happen
427
            // in editing process when a field has been added
428
            // in the current editing session, so we simply do nothing.
429
            // The expansion manager is expected to manage those new fields
430
            // and their values.
431
            this.logger.warn("The requested field ("+descriptor.getName()+") does not exist in the DBF file. Assumed it's a new field in editing mode.");
432
            return;
433
        }
434

    
435
        String value = null;
436
        try {
437
            value = this.dbfFile.getStringFieldValue(rowIndex, dbfFieldIndex);
438
        } catch (DataException e) {
439
            throw new ReadException(this.getName(), e);
440
        }
441
        value = value.trim();
442
        FieldFormatter formatter = new FieldFormatter();
443
        
444
        int index = descriptor.getIndex();
445
        Object defaultValue = descriptor.getDefaultValueCoerced();
446
        
447
        switch (descriptor.getType()) {
448
            case DataTypes.STRING:
449
                featureProvider.set(index, formatter.parseString(value, (String) defaultValue));
450
                break;
451

    
452
            case DataTypes.DECIMAL:
453
                BigDecimal d = formatter.parseDecimal(
454
                    value,
455
                    descriptor.getMathContext(),
456
                    descriptor.getScale(),
457
                    (BigDecimal) defaultValue
458
                );
459
                if (!BigDecimalUtils.isValid(d, descriptor.getScale(), descriptor.getPrecision())) {
460
                    DBFStoreParameters params = this.getDBFParameters();
461
                    if(params.allowInconsistenciesInDecimals() ) {
462
                        MutableInt scale = new MutableInt(descriptor.getScale());
463
                        MutableInt precision = new MutableInt(descriptor.getPrecision());
464
                        d = BigDecimalUtils.fixIfCan(d, scale, precision);
465
                        updateStoreScaleAndPrecision(featureProvider, descriptor, scale.intValue(), precision.intValue());
466
                    } else {
467
                        FeatureType storeFeatureType = featureProvider.getStoreFeatureType();
468
                        if(storeFeatureType != null){
469
                            FeatureAttributeDescriptor storeDescriptor = storeFeatureType.getAttributeDescriptor(descriptor.getName());
470
                            if (storeDescriptor instanceof EditableFeatureAttributeDescriptor && BigDecimalUtils.isValid(d, storeDescriptor.getScale(), storeDescriptor.getPrecision())) {
471
                                ((EditableFeatureAttributeDescriptor)descriptor).setScale(storeDescriptor.getScale());
472
                                ((EditableFeatureAttributeDescriptor)descriptor).setPrecision(storeDescriptor.getPrecision());
473
                            }
474
                        }
475
                    }
476
                }
477
                featureProvider.set(index,d);
478
                break;
479

    
480
            case DataTypes.DOUBLE:
481
                featureProvider.set(index, formatter.parseDouble(value, (Double) defaultValue));
482
                break;
483

    
484
            case DataTypes.FLOAT:
485
                featureProvider.set(index, formatter.parseFloat(value, (Float) defaultValue));
486
                break;
487

    
488
            case DataTypes.LONG:
489
                featureProvider.set(index, formatter.parseLong(value, (Long) defaultValue));
490
                break;
491

    
492
            case DataTypes.INT:
493
                featureProvider.set(index, formatter.parseInt(value, (Integer) defaultValue));
494
                break;
495

    
496
            case DataTypes.BYTE:
497
                featureProvider.set(index, formatter.parseByte(value, (Byte) defaultValue));
498
                break;
499

    
500
            case DataTypes.BOOLEAN:
501
                featureProvider.set(index, formatter.parseBoolean(value, (Boolean) defaultValue));
502
                break;
503

    
504
            case DataTypes.TIMESTAMP:
505
                featureProvider.set(index, formatter.parseTimestamp(value, (java.sql.Timestamp) defaultValue));
506
                break;
507
                
508
            case DataTypes.TIME:
509
                featureProvider.set(index, formatter.parseTime(value, (java.sql.Time) defaultValue));
510
                break;
511

    
512
            case DataTypes.DATE:
513
                featureProvider.set(index, formatter.parseDate(value, (java.sql.Date) defaultValue));
514
                break;
515

    
516
            default: {
517
                    Object v;
518
                    try {
519
                        v = descriptor.getDataType().coerce(value);
520
                    } catch (CoercionException ex) {
521
                        v = defaultValue;
522
                    }
523
                    featureProvider.set(index, v);
524
                }
525
                break;
526
        }
527
    }
528

    
529
    protected FeatureProvider getFeatureProviderByIndex(long index) throws DataException {
530
        return this
531
                .getFeatureProviderByIndex(index, this.getStoreServices()
532
                        .getDefaultFeatureType(), null);
533
    }
534

    
535
    @Override
536
    public long getFeatureCount() throws ReadException, OpenException,
537
            ResourceNotifyChangesException {
538
        this.open();
539
        return (long) getResource().execute(() -> (long) dbfFile.getRecordCount());
540
    }
541

    
542
    @Override
543
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
544
            throws DataException {
545
        return new DBFSetProvider(this, query, featureType, null);
546
    }
547

    
548
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType providerFeatureType, FeatureType storeFeatureType)
549
            throws DataException {
550
        return new DBFSetProvider(this, query, providerFeatureType, storeFeatureType);
551
    }
552

    
553
    public boolean canCreate() {
554
        return true;
555
    }
556

    
557
    public boolean canWriteGeometry(int geometryType, int geometrySubType) throws DataException {
558
        return false;
559
    }
560

    
561
    public void open() throws OpenException {
562
        if (this.dbfFile.isOpen()) {
563
            return;
564
        }
565
        try {
566
            getResource().execute(new ResourceAction() {
567
                public Object run() throws Exception {
568
                    openFile();
569
                    resourcesOpen();
570
                    return null;
571
                }
572
            });
573

    
574
        } catch (ResourceExecuteException e) {
575
            throw new OpenException(this.getProviderName(), e);
576
        }
577
    }
578

    
579
    protected void openFile() throws FileNotFoundException,
580
            UnsupportedVersionException, IOException, DataException {
581
        this.dbfFile.open();
582
        // necessary when editing the file
583
        this.getDBFParameters().setEffectiveEncoding(this.dbfFile.getCharsetName());
584
    }
585

    
586
    public void close() throws CloseException {
587
        if( loTengoEnUso ) {
588
            return;
589
        }
590
        if (dbfFile == null || !this.dbfFile.isOpen()) {
591
            return;
592
        }
593
        super.close();
594

    
595
        //Cerrar recurso
596
        try {
597
            getResource().execute(new ResourceAction() {
598
                public Object run() throws Exception {
599
                    closeFile();
600
                    resourcesNotifyClose();
601
                    return null;
602
                }
603
            });
604
        } catch (ResourceExecuteException  e) {
605
            throw new CloseException(this.getProviderName(), e);
606
        }
607
    }
608

    
609
    protected void closeFile() throws CloseException {
610
        this.dbfFile.close();
611
    }
612

    
613
    @Override
614
    protected void doDispose() throws BaseException {
615
        this.close();
616
        dbfFile = null;
617
        disposeResource();
618
        super.doDispose();
619
    }
620

    
621
    protected void disposeResource() {
622
        this.dbfResource.removeConsumer(this);
623
        dbfResource = null;
624
    }
625

    
626
    public boolean closeResourceRequested(ResourceProvider resource) {
627
        try {
628
            this.close();
629
        } catch (CloseException e) {
630
            return false;
631
        }
632
        return true;
633
    }
634

    
635
    public boolean allowWrite() {
636
        if(allowDuplicatedFieldNames || this.getDBFParameters().allowInconsistenciesInDecimals()){
637
            return false;
638
        }
639
        return this.dbfFile.isWritable();
640
    }
641

    
642
    public void refresh() throws OpenException {
643
        try {
644
            this.close();
645
        } catch (CloseException e) {
646
            throw new OpenException(this.getProviderName(), e);
647
        }
648
        this.open();
649
        try {
650
            this.initFeatureType();
651
        } catch (InitializeException e) {
652
            throw new OpenException(this.getProviderName(), e);
653
        }
654
    }
655

    
656
    protected FeatureProvider getFeatureProviderByIndex(long index,
657
            FeatureType providerFeatureType, FeatureType storeFeatureType) throws DataException {
658
        FeatureProvider featureProvider = this.createFeatureProvider(providerFeatureType, storeFeatureType);
659
        featureProvider.setOID(index);
660
        return featureProvider;
661
    }
662

    
663
    protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
664
            long index, FeatureType featureType) throws DataException {
665
        featureProvider.setOID(index);
666
    }
667

    
668
    protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
669
            throws DataException {
670

    
671
        long index = ((Long) featureProvider.getOID());
672
        int rec_count = this.dbfFile.getRecordCount();
673

    
674
        if (index >= rec_count) {
675

    
676
            ReadException rex = new ReadException(this.getName(),
677
                    new ArrayIndexOutOfBoundsException(
678
                            "Index of requested feature ("
679
                            + index + ") is >= record count (" + rec_count + ")"));
680

    
681
            LOG.info("Error while loading feature. ", rex);
682
            throw rex;
683
        }
684

    
685
//        long t1 = System.nanoTime();
686
        ((DBFFeatureProvider)featureProvider).setBroken(false);
687
        for (FeatureAttributeDescriptor desc : featureProvider.getType()) {
688
            try {
689
                this.loadValue((DBFFeatureProvider)featureProvider, index, desc);
690
            } catch (Throwable th) {
691
                this.logger.warn("Can't load value for attribute '"+desc.getName()+"'", th);
692
                ((DBFFeatureProvider)featureProvider).setBroken(true);
693
                featureProvider.set(desc.getIndex(), null);
694
            }
695
        }
696
//        long t2 = System.nanoTime();
697
//        LOG.info("load "+index+" in :"+(t2-t1));
698
    }
699

    
700
    @Override
701
    public int getOIDType() {
702
        return DataTypes.LONG;
703
    }
704

    
705
    @Override
706
    public Object createNewOID() {
707
        if (this.counterNewsOIDs < 0) {
708
            try {
709
                this.counterNewsOIDs = this.getFeatureCount();
710
            } catch (DataException e) {
711
                LOG.warn("Can't initialice counter for news OIDs.",e);
712
            }
713

    
714
        } else {
715
            this.counterNewsOIDs++;
716
        }
717
        return counterNewsOIDs;
718
    }
719

    
720
    @Override
721
    public boolean supportsAppendMode() {
722
        return true;
723
    }
724

    
725
    @Override
726
    public void append(final FeatureProvider featureProvider)
727
            throws DataException {
728
        getResource().execute(() -> {
729
            writer.append(getStoreServices().createFeature(featureProvider));
730
            return null;
731
        });
732
    }
733

    
734
    @Override
735
    public void beginAppend() throws DataException {
736
        this.close();
737
        getResource().execute(() -> {
738
            writer.begin(getDBFParameters(),
739
                    getStoreServices().getDefaultFeatureType(),
740
                    getStoreServices().getFeatureStore().getFeatureCount());
741
            return null;
742
        });
743
    }
744

    
745
    public void endAppend() throws DataException {
746
        getResource().execute(new ResourceAction() {
747
            public Object run() throws Exception {
748
                writer.end();
749
                resourcesNotifyChanges();
750
                counterNewsOIDs = -1;
751
                return null;
752
            }
753
        });
754
    }
755

    
756
    public void resourceChanged(ResourceProvider resource) {
757
        if (this.getStoreServices()!=null){
758
            this.getStoreServices().notifyChange(
759
                    DataStoreNotification.RESOURCE_CHANGED,
760
                    resource);
761
        }
762
    }
763

    
764
    protected void resourcesNotifyChanges()
765
            throws ResourceNotifyChangesException {
766
        this.dbfResource.notifyChanges();
767
    }
768

    
769
    protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
770
        this.dbfResource.notifyClose();
771
    }
772

    
773
    protected void resourcesOpen() throws ResourceNotifyOpenException {
774
        this.dbfResource.notifyOpen();
775
    }
776

    
777
    public Object getSourceId() {
778
        return this.getDBFParameters().getFile();
779
    }
780

    
781
    public String getName() {
782
        String name = this.getDBFParameters().getFile().getName();
783
        int n = name.lastIndexOf(".");
784
        if (n < 1) {
785
            return name;
786
        }
787
        return name.substring(0, n);
788
    }
789

    
790
    public String getFullName() {
791
        return this.getDBFParameters().getFile().getAbsolutePath();
792
    }
793

    
794
    protected void resourceCloseRequest() throws ResourceException {
795
        this.dbfResource.closeRequest();
796
    }
797

    
798
    public ResourceProvider getResource() {
799
        return dbfResource;
800
    }
801
    
802
    @Override
803
    public void fixFeatureTypeFromParameters() {
804
        FeatureStoreProviderServices store = this.getStoreServices();
805
        try {
806
            int sizeWithoutComputed = 0;
807
            for (FeatureAttributeDescriptor featureAttributeDescriptor : store.getDefaultFeatureType()) {
808
                if (featureAttributeDescriptor.isComputed()) {
809
                    continue;
810
                }
811
                sizeWithoutComputed +=1;
812
            }
813
            if(this.featureType.size()!=sizeWithoutComputed) {
814
                this.setStoreFeatureType(featureType.getNotEditableCopy());
815
            }
816
        } catch (DataException ex) {
817
            
818
        }
819
    }
820

    
821
    private void updateStoreScaleAndPrecision(DBFFeatureProvider featureProvider, FeatureAttributeDescriptor descriptor, int scale, int precision) {
822
        if(descriptor.getType() == DataTypes.DECIMAL){
823
            if(descriptor.getScale() == scale && descriptor.getPrecision() == precision) {
824
                return;
825
            }
826
            FeatureType ft = this.getFeatureStore().getDefaultFeatureTypeQuietly();
827
            FeatureAttributeDescriptor d = ft.getAttributeDescriptor(descriptor.getName());
828
            if(d.getScale() == scale && d.getPrecision() == precision) {
829
                ((DBFFeatureProvider)featureProvider).setProviderFeatureType(ft);
830
                return;
831
            }
832
            EditableFeatureType eft = ft.getEditable();
833
            EditableFeatureAttributeDescriptor ed = (EditableFeatureAttributeDescriptor) eft.getAttributeDescriptor(descriptor.getName());
834
            ed.setScale(scale);
835
            ed.setPrecision(precision);
836
            ft = eft.getNotEditableCopy();
837
            ((DBFFeatureProvider)featureProvider).setProviderFeatureType(ft);
838
            this.setStoreFeatureType(ft);
839
        }
840
    }
841

    
842
}