Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / spi / JDBCServerExplorerBase.java @ 46542

History | View | Annotate | Download (42.3 KB)

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

    
26
import org.gvsig.tools.resourcesstorage.CompoundResourcesStorage;
27
import java.io.File;
28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.Collections;
31
import java.util.HashMap;
32
import java.util.List;
33
import java.util.Map;
34
import java.util.Objects;
35
import javax.json.JsonObject;
36
import javax.json.JsonString;
37
import javax.json.JsonValue;
38
import org.apache.commons.codec.binary.Hex;
39
import org.apache.commons.collections.map.LRUMap;
40
import org.apache.commons.lang3.BooleanUtils;
41
import org.apache.commons.lang3.ObjectUtils;
42
import org.apache.commons.lang3.StringUtils;
43
import org.apache.commons.lang3.tuple.ImmutablePair;
44
import org.apache.commons.lang3.tuple.Pair;
45
import org.gvsig.expressionevaluator.ExpressionBuilder;
46
import org.gvsig.expressionevaluator.ExpressionUtils;
47
import org.gvsig.fmap.dal.DALLocator;
48
import org.gvsig.fmap.dal.DataManager;
49
import org.gvsig.fmap.dal.DataStore;
50
import org.gvsig.fmap.dal.DataStoreParameters;
51
import org.gvsig.fmap.dal.DataTransaction;
52
import org.gvsig.fmap.dal.DatabaseWorkspaceManager;
53
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_NAME;
54
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_VALUE;
55
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_CONFIGURATION_NAME;
56
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_RESOURCES_NAME;
57
import org.gvsig.fmap.dal.NewDataStoreParameters;
58
import org.gvsig.fmap.dal.SQLBuilder;
59
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
60
import org.gvsig.fmap.dal.exception.CloseException;
61
import org.gvsig.fmap.dal.exception.DataException;
62
import org.gvsig.fmap.dal.exception.InitializeException;
63
import org.gvsig.fmap.dal.exception.OpenException;
64
import org.gvsig.fmap.dal.exception.RemoveException;
65
import org.gvsig.fmap.dal.feature.EditableFeature;
66
import org.gvsig.fmap.dal.feature.EditableFeatureType;
67
import org.gvsig.fmap.dal.feature.Feature;
68
import org.gvsig.fmap.dal.feature.FeatureStore;
69
import org.gvsig.fmap.dal.feature.FeatureType;
70
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
71
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
72
import org.gvsig.fmap.dal.serverexplorer.db.spi.AbstractDBServerExplorer;
73
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemStoreParameters;
74
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
75
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
76
import org.gvsig.fmap.dal.spi.DataTransactionServices;
77
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
78
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
79
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
80
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
81
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
82
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
83
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
84
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
85
import static org.gvsig.fmap.dal.store.jdbc2.spi.JDBCResourcesStorage.TABLENAME_SERVER_EXPLORER_MARK;
86
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CanCreateTablesOperation;
87
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CreateTableOperation;
88
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.DropTableOperation;
89
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.ExecuteOperation;
90
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
91
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.ListTablesOperation;
92
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.RetrieveValueOperation;
93
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.UpdateTableStatisticsOperation;
94
import org.gvsig.json.Json;
95
import org.gvsig.json.JsonObjectBuilder;
96
import org.gvsig.tools.ToolsLocator;
97
import org.gvsig.tools.dispose.DisposeUtils;
98
import org.gvsig.tools.exception.BaseException;
99
import org.gvsig.tools.resourcesstorage.EmptyResourcesStorage;
100
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
101
import org.gvsig.tools.util.CachedValue;
102
import org.slf4j.Logger;
103
import org.slf4j.LoggerFactory;
104

    
105
@SuppressWarnings("UseSpecificCatch")
106
public class JDBCServerExplorerBase extends AbstractDBServerExplorer implements JDBCServerExplorer {
107

    
108
    private static final Logger LOG = LoggerFactory.getLogger(JDBCServerExplorerBase.class);
109
    private static final String CONFIG_NAME_CUSTOM_RESOURCES = "CUSTOM_RESOURCES";
110

    
111
    protected JDBCHelper helper = null;
112

    
113
    private Boolean canAdd;
114

    
115
    private static final Map<String, CachedValue<List<JDBCStoreParameters>>> CACHED_TABLES = Collections.synchronizedMap(new LRUMap(10));
116
    private static final Map<String, CachedValue<CustomResourcesConfig>> CACHED_CUSTOM_RESOURCES_CONFIG = Collections.synchronizedMap(new LRUMap(10));
117

    
118
    private static class CustomResourcesConfig {
119

    
120
        private static final String CUSTOM_RESOURCES_CACHETIME = "CacheTime";
121
        private static final String CUSTOM_RESOURCES_MAPPING = "Mapping";
122
        private static final String CUSTOM_RESOURCES_READONLY = "ResourcesReadonly";
123

    
124

    
125
        private int cacheTime;
126
        private Map<String, String> mapping;
127
        private Map<String,Boolean> resourcesReadonly;
128
        
129
        public CustomResourcesConfig(String jsonConfig) {
130
            this.cacheTime = 30*60*1000; // 30min
131
            this.mapping = new HashMap<>();
132
            this.resourcesReadonly = new HashMap<>();
133
            
134
            if (StringUtils.isNotBlank(jsonConfig)) {
135
                try {
136
                    JsonObject config = Json.createObject(jsonConfig);
137
                    this.cacheTime = config.getInt(CUSTOM_RESOURCES_CACHETIME, this.cacheTime);
138
                    if (config.containsKey(CUSTOM_RESOURCES_MAPPING)) {
139
                        JsonObject m = config.getJsonObject(CUSTOM_RESOURCES_MAPPING);
140
                        for (Map.Entry<String, JsonValue> entry : m.entrySet()) {
141
                            String key = entry.getKey();
142
                            JsonValue value = entry.getValue();
143
                            if (value instanceof JsonString) {
144
                                this.mapping.put(key, ((JsonString) value).getString());
145
                            }
146
                        }
147
                    }
148
                    if (config.containsKey(CUSTOM_RESOURCES_READONLY)) {
149
                        JsonObject resreadonly = config.getJsonObject(CUSTOM_RESOURCES_READONLY);
150
                        for (Map.Entry<String, JsonValue> entry : resreadonly.entrySet()) {
151
                            String key = entry.getKey();
152
                            JsonValue value = entry.getValue();
153
                            if (value == JsonValue.TRUE) {
154
                                this.resourcesReadonly.put(key, true);
155
                            } else if (value == JsonValue.FALSE) {
156
                                this.resourcesReadonly.put(key, false);
157
                            }
158
                        }
159
                    }
160
                } catch (Exception ex) {
161
                    LOG.debug("Can't parse json from "+CONFIG_NAME_CUSTOM_RESOURCES+" variable", ex);
162
                    // Do nothing.
163
                }
164
            }
165
        }
166

    
167
        public String toJsonString() {
168
            JsonObjectBuilder builder = Json.createObjectBuilder();
169
            builder.add(CUSTOM_RESOURCES_CACHETIME, this.cacheTime);
170
            JsonObjectBuilder m = Json.createObjectBuilder();
171
            for (Map.Entry<String, String> entry : this.mapping.entrySet()) {
172
                String key = entry.getKey();
173
                String value = entry.getValue();
174
                m.add(key, value);
175
            }
176
            builder.add(CUSTOM_RESOURCES_MAPPING, m);
177
            JsonObjectBuilder resreadonly = Json.createObjectBuilder();
178
            for (Map.Entry<String, Boolean> entry : this.resourcesReadonly.entrySet()) {
179
                String key = entry.getKey();
180
                Boolean readonly = entry.getValue();
181
                resreadonly.add(key,readonly);
182
            }
183
            builder.add(CUSTOM_RESOURCES_READONLY, resreadonly);
184
            return builder.build().toString();
185
        }
186

    
187
        public int getCacheExpireTimeInMillis() {
188
            return cacheTime;
189
        }
190

    
191
        public String getResourcesTablename(String tablename) {
192
            String resourceTablename = mapping.get(tablename);
193
//            LOG.info("Resource of table "+tablename+" = "+resourceTablename);
194
            return resourceTablename;
195
        }
196

    
197
        public void addResourceMapping(String tablename, String resourcesTablename) {
198
            this.mapping.put(tablename, resourcesTablename);
199
        }
200

    
201
        private boolean isInternalTable(String storeName) {
202
            if (DatabaseWorkspaceManager.isInternalTable(storeName)) {
203
                return true;
204
            }
205
            for (String resourcesTablename : this.mapping.values()) {
206
                if( StringUtils.equals(storeName, resourcesTablename) ) {
207
                    return true;
208
                }
209
            }
210
            return false;
211
        }
212

    
213
        public void setResourcesReadOnly(String resourcesTableName, boolean readonly) {
214
            this.resourcesReadonly.put(resourcesTableName,readonly);
215
        }
216
        
217
        public boolean isResourcesReadOnly(String resourcesTableName) {
218
            return this.resourcesReadonly.getOrDefault(resourcesTableName,false);
219
        }
220
    }
221
    
222
    private static class CachedCustomResourcesConfig extends CachedValue<CustomResourcesConfig> {
223

    
224
        private final JDBCStoreParameters openParameters;
225

    
226
        private CachedCustomResourcesConfig(JDBCStoreParameters openParameters) {
227
            this.openParameters = openParameters;
228
            this.setExpireTime(30*60*1000); // 30min
229
        }
230

    
231
        @Override
232
        protected void reload() {
233
            String jsonConfig = getConfigValue(this.openParameters, CONFIG_NAME_CUSTOM_RESOURCES);
234
//            LOGGER.info("reload CustomResourcesConfig "+jsonConfig);
235
            CustomResourcesConfig config = new CustomResourcesConfig(jsonConfig);        
236
            this.setExpireTime(config.getCacheExpireTimeInMillis());
237
            this.setValue(config);
238
        }
239
        
240
    }
241

    
242
    private static class CachedTablesValue extends CachedValue<List<JDBCStoreParameters>> {
243

    
244
        private final int mode;
245
        private final JDBCServerExplorerParameters serverParameters;
246
        private final boolean informationTables;
247
        private JDBCHelper helper;
248
        private final int tablesOrViews;
249

    
250
        public CachedTablesValue(JDBCHelper helper, int mode, JDBCServerExplorerParameters serverParameters, boolean informationTables, int tablesOrViews) {
251
            this.mode = mode;
252
            this.serverParameters = serverParameters;
253
            this.informationTables = informationTables;
254
            this.helper = helper;
255
            this.tablesOrViews = tablesOrViews;
256
        }
257

    
258
        public CachedTablesValue(JDBCHelper helper, int mode, JDBCServerExplorerParameters serverParameters, boolean informationTables, long expireTime, int tablesOrViews) {
259
            this.mode = mode;
260
            this.setExpireTime(expireTime);
261
            this.serverParameters = serverParameters;
262
            this.informationTables = informationTables;
263
            this.helper = helper;
264
            this.tablesOrViews = tablesOrViews;
265
        }
266

    
267
        @Override
268
        protected void reload() {
269
//            LOGGER.info("reload list of tables");
270
            List<JDBCStoreParameters> tables = null;
271
            if(helper == null){
272
                this.setValue(tables);
273
                return;
274
            }
275
            OperationsFactory operations = helper.getOperations();
276
            if (operations == null) {
277
                this.setValue(null);
278
                LOG.debug("Sets tables to null to force reload tables from new ServerExplorar.");
279
                return;
280
            }
281
            try {
282
                ListTablesOperation listTables = operations.createListTables(
283
                        this.mode, serverParameters, informationTables, tablesOrViews
284
                );
285
                tables = (List<JDBCStoreParameters>) listTables.perform();
286
            } catch (Exception ex) {
287
                LOG.debug("Can't reload cached list of tables.", ex);
288
            }
289
            this.setValue(tables);
290
        }
291
        
292
        public JDBCHelper getHelper(){
293
            return this.helper;
294
        }
295
        
296
        public void dispose() {
297
            this.helper = null;
298
        }
299
    }
300

    
301
    public JDBCServerExplorerBase(
302
            JDBCServerExplorerParameters parameters,
303
            DataServerExplorerProviderServices services,
304
            JDBCHelper helper
305
    ) throws InitializeException {
306
        super(parameters, services);
307
        this.helper = helper;
308
    }
309

    
310
    @Override
311
    public String getProviderName() {
312
        return this.getHelper().getProviderName();
313
    }
314

    
315
    @Override
316
    public String getStoreName() {
317
        return this.getHelper().getProviderName();
318
    }
319

    
320
    protected DataManagerProviderServices getManager() {
321
        return (DataManagerProviderServices) DALLocator.getDataManager();
322
    }
323

    
324
    @Override
325
    public JDBCServerExplorerParameters getParameters() {
326
        return (JDBCServerExplorerParameters) super.getParameters();
327
    }
328

    
329
    @Override
330
    public boolean closeResourceRequested(ResourceProvider resource) {
331
        this.getHelper().getResulSetControler().pack();
332
        return true;
333
    }
334

    
335
    @Override
336
    public void resourceChanged(ResourceProvider resource) {
337
        // Nothing to do
338
    }
339

    
340
    protected JDBCHelper getHelper() {
341
        return helper;
342
    }
343

    
344
    protected OperationsFactory getOperations() {
345
        return this.getHelper().getOperations();
346
    }
347

    
348
    @Override
349
    public DataStore open(DataStoreParameters params) throws DataException {
350
        checkIsMine(params);
351
        DataStore store = super.open(params);
352
        return store;
353
    }
354

    
355
    @Override
356
    public DataStore open(String tableName) throws DataException {
357
        JDBCStoreParameters params = this.get(tableName);
358
        DataStore store = super.open(params);
359
        return store;
360
    }
361

    
362
    @Override
363
    public List list(int mode) throws DataException {
364
        return list(mode, SHOW_TABLES_AND_VIEWS);
365
    }
366

    
367
    @Override
368
    public List list(int mode, int tablesOrViews) throws DataException {
369
        boolean informationTables = BooleanUtils.isTrue(
370
                this.getParameters().getShowInformationDBTables()
371
        );
372

    
373
        JDBCServerExplorerParameters serverParams = this.getParameters();
374

    
375
        String key = buildKeyForCachedTables(mode, serverParams, informationTables, tablesOrViews);
376
        CachedValue<List<JDBCStoreParameters>> tablesValue = CACHED_TABLES.get(key);
377
        List<JDBCStoreParameters> tables = null;
378
        if (tablesValue != null) {
379
            tables = tablesValue.get();
380
        }
381
        if (tables != null) {
382
            return tables;
383
        }
384
        tablesValue = new CachedTablesValue(this.helper, mode, serverParams, informationTables, 60000, tablesOrViews); //60"
385
        CACHED_TABLES.put(key, tablesValue);
386
        tables = tablesValue.get();
387
        return tables;
388
    }
389

    
390
    public String buildKeyForCachedTables(int mode, JDBCServerExplorerParameters params, boolean informationTables, int tablesOrViews) {
391
        JDBCServerExplorerParameters clonedParams = (JDBCServerExplorerParameters) params.getCopy();
392
        clonedParams.setSchema(null); 
393
        clonedParams.setCatalog(null); 
394

    
395
        StringBuilder builder = new StringBuilder();
396
        builder.append(String.valueOf(mode));
397
        builder.append(Hex.encodeHex(clonedParams.toByteArray()));
398
        builder.append(String.valueOf(informationTables));
399
        builder.append(String.valueOf(tablesOrViews));
400
        String key = builder.toString();
401
        return key;
402
    }
403

    
404
    @Override
405
    public void remove(DataStoreParameters theParams) throws RemoveException {
406
        JDBCStoreParameters params = (JDBCStoreParameters) theParams;
407
        DropTableOperation removeTable = this.getOperations().createDropTable(
408
                this.getOperations().createTableReference(params)
409
        );
410
        if ((Boolean) removeTable.perform()) {
411
            this.dropCachedTables();
412
        }
413
    }
414

    
415
    @Override
416
    public JDBCStoreParameters getOpenParameters() throws DataException {
417
        JDBCStoreParameters params = this.helper.createOpenStoreParameters(this.getParameters());
418
        return params;
419
    }
420

    
421
    @Override
422
    public NewDataStoreParameters getAddParameters(String storeName)
423
            throws DataException {
424
        JDBCNewStoreParameters params = this.getAddParameters();
425
        params.setTable(storeName);
426
        return params;
427
    }
428

    
429
    @Override
430
    public JDBCNewStoreParameters getAddParameters() throws DataException {
431
        JDBCServerExplorerParameters parameters = getParameters();
432
        JDBCNewStoreParameters params = this.helper.createNewStoreParameters();
433
        params.setHost(parameters.getHost());
434
        params.setPort(parameters.getPort());
435
        params.setDBName(parameters.getDBName());
436
        params.setUser(parameters.getUser());
437
        params.setPassword(parameters.getPassword());
438
        params.setCatalog(parameters.getCatalog());
439
        params.setSchema(parameters.getSchema());
440
        params.setJDBCDriverClassName(parameters.getJDBCDriverClassName());
441
        params.setUrl(parameters.getUrl());
442
        if (parameters instanceof FilesystemStoreParameters) {
443
            File f = ((FilesystemStoreParameters) parameters).getFile();
444
            ((FilesystemStoreParameters) params).setFile(f);
445
        }
446

    
447
        params.setDefaultFeatureType(this.getServerExplorerProviderServices()
448
                .createNewFeatureType());
449

    
450
        return params;
451
    }
452

    
453
    protected void checkIsMine(DataStoreParameters dsp) {
454
        if (!(dsp instanceof JDBCConnectionParameters)) {
455
            throw new IllegalArgumentException(
456
                    "not instance of FilesystemStoreParameters");
457
        }
458
        JDBCServerExplorerParameters parameters = getParameters();
459

    
460
        JDBCConnectionParameters pgp = (JDBCConnectionParameters) dsp;
461
        if (!StringUtils.equals(pgp.getHost(), parameters.getHost())) {
462
            throw new IllegalArgumentException("wrong explorer: Host (mine: "
463
                    + parameters.getHost() + " other:" + pgp.getHost() + ")");
464
        }
465
        if (!ObjectUtils.equals(pgp.getPort(), parameters.getPort())) {
466
            throw new IllegalArgumentException("wrong explorer: Port (mine: "
467
                    + parameters.getPort() + " other:" + pgp.getPort() + ")");
468
        }
469
        if (!StringUtils.equals(pgp.getDBName(), parameters.getDBName())) {
470
            throw new IllegalArgumentException("wrong explorer: DBName (mine: "
471
                    + parameters.getDBName() + " other:" + pgp.getDBName()
472
                    + ")");
473
        }
474
        if (!StringUtils.isEmpty(parameters.getCatalog())) {
475
            if (!StringUtils.equals(pgp.getCatalog(), parameters.getCatalog())) {
476
                throw new IllegalArgumentException(
477
                        "wrong explorer: Catalog (mine: "
478
                        + parameters.getCatalog() + " other:"
479
                        + pgp.getCatalog() + ")");
480
            }
481
        }
482
        if (!StringUtils.isEmpty(parameters.getSchema())) {
483
            if (!StringUtils.equals(pgp.getSchema(), parameters.getSchema())) {
484
                throw new IllegalArgumentException(
485
                        "wrong explorer: Schema (mine: "
486
                        + parameters.getSchema() + " other:"
487
                        + pgp.getSchema() + ")");
488
            }
489
        }
490
    }
491

    
492
    @Override
493
    public void open() throws OpenException {
494

    
495
    }
496

    
497
    @Override
498
    public void close() throws CloseException {
499

    
500
    }
501

    
502
    @Override
503
    protected void doDispose() throws BaseException {
504
        synchronized (CACHED_TABLES) {
505
            List<String> toRemove = new ArrayList<>();
506
            for (Map.Entry<String, CachedValue<List<JDBCStoreParameters>>> entry : CACHED_TABLES.entrySet()) {
507
                CachedTablesValue value = (CachedTablesValue) entry.getValue();
508
                if (value.getHelper() == this.helper) {
509
                    toRemove.add(entry.getKey());
510
                    value.dispose();
511
                }
512
            }
513
            for (String key : toRemove) {
514
                CACHED_TABLES.remove(key);
515
            }
516
            helper.dispose();
517
            helper = null;
518
        }
519
    }
520

    
521
    @Override
522
    public boolean canAdd() {
523
        if (this.canAdd == null) {
524
            CanCreateTablesOperation canAdd_ = this.getOperations().createCanCreateTables();
525
            this.canAdd = (Boolean) canAdd_.perform();
526
        }
527
        return this.canAdd;
528
    }
529

    
530
    @Override
531
    public FeatureType getFeatureType(DataStoreParameters theParams)
532
            throws DataException {
533

    
534
        JDBCStoreParameters params = (JDBCStoreParameters) theParams;
535

    
536
        checkIsMine(params);
537

    
538
        EditableFeatureType fetureType
539
                = this.getServerExplorerProviderServices().createNewFeatureType();
540

    
541
        List<String> primaryKeys = null;
542
        if (params.getPkFields() != null) {
543
            primaryKeys = Arrays.asList(params.getPkFields());
544
        }
545

    
546
        FetchFeatureTypeOperation fetch = this.getOperations().createFetchFeatureType(
547
                fetureType,
548
                this.getOperations().createTableReference(params),
549
                primaryKeys,
550
                params.getDefaultGeometryField(),
551
                params.getCRS()
552
        );
553
        fetch.perform();
554
        return fetureType;
555
    }
556

    
557
    @Override
558
    public boolean add(String providerName, NewDataStoreParameters theParams, boolean overwrite)
559
            throws DataException {
560

    
561
        List<Pair<String, Privilege>> userAndPrivileges = new ArrayList<>();
562
        JDBCNewStoreParameters params = (JDBCNewStoreParameters) theParams;
563
        if (!StringUtils.isEmpty(params.getAllRole())) {
564
            userAndPrivileges.add(
565
                    new ImmutablePair<>(params.getAllRole(), Privilege.ALL)
566
            );
567
        }
568
        if (!StringUtils.isEmpty(params.getDeleteRole())) {
569
            userAndPrivileges.add(
570
                    new ImmutablePair<>(params.getDeleteRole(), Privilege.DELETE)
571
            );
572
        }
573
        if (!StringUtils.isEmpty(params.getInsertRole())) {
574
            userAndPrivileges.add(
575
                    new ImmutablePair<>(params.getInsertRole(), Privilege.INSERT)
576
            );
577
        }
578
        if (!StringUtils.isEmpty(params.getReferenceRole())) {
579
            userAndPrivileges.add(
580
                    new ImmutablePair<>(params.getReferenceRole(), Privilege.REFERENCE)
581
            );
582
        }
583
        if (!StringUtils.isEmpty(params.getSelectRole())) {
584
            userAndPrivileges.add(
585
                    new ImmutablePair<>(params.getSelectRole(), Privilege.SELECT)
586
            );
587
        }
588
        if (!StringUtils.isEmpty(params.getTriggerRole())) {
589
            userAndPrivileges.add(
590
                    new ImmutablePair<>(params.getTriggerRole(), Privilege.TRIGGER)
591
            );
592
        }
593
        if (!StringUtils.isEmpty(params.getTruncateRole())) {
594
            userAndPrivileges.add(
595
                    new ImmutablePair<>(params.getTruncateRole(), Privilege.TRUNCATE)
596
            );
597
        }
598
        if (!StringUtils.isEmpty(params.getUpdateRole())) {
599
            userAndPrivileges.add(
600
                    new ImmutablePair<>(params.getUpdateRole(), Privilege.UPDATE)
601
            );
602
        }
603
        List<String> additionalSQLs = new ArrayList<>();
604
        if (!StringUtils.isEmpty(params.getPostCreatingStatement())) {
605
            additionalSQLs.add(params.getPostCreatingStatement());
606
        }
607
        CreateTableOperation createTable = this.getOperations().createTable(
608
                this.getOperations().createTableReference(params),
609
                params.getDefaultFeatureType(),
610
                userAndPrivileges,
611
                additionalSQLs
612
        );
613

    
614
        boolean isOk = (boolean) createTable.perform();
615
        if (!isOk) {
616
            return false;
617
        }
618

    
619
        // We collect the featureType of the operation because 
620
        // the provider has been able to make changes to it
621
        params.setDefaultFeatureType(createTable.getType());
622

    
623
        if (theParams instanceof NewFeatureStoreParameters) {
624
            DataManager dataManager = DALLocator.getDataManager();
625
            ResourcesStorage resources = this.getResourcesStorage(theParams);
626
            dataManager.writeDALResource(resources, ((NewFeatureStoreParameters) theParams).getDefaultFeatureType());
627
        }
628
        this.dropCachedTables();
629
        return true;
630
    }
631

    
632
    private void dropCachedTables() {
633
        boolean informationTables = BooleanUtils.isTrue(
634
                this.getParameters().getShowInformationDBTables()
635
        );
636
        synchronized(CACHED_TABLES){
637
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_ALL, this.getParameters(), informationTables, SHOW_TABLES_AND_VIEWS));
638
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_FEATURE, this.getParameters(), informationTables, SHOW_TABLES_AND_VIEWS));
639
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_GEOMETRY, this.getParameters(), informationTables, SHOW_TABLES_AND_VIEWS));
640
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_ALL, this.getParameters(), informationTables, SHOW_TABLES));
641
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_FEATURE, this.getParameters(), informationTables, SHOW_TABLES));
642
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_GEOMETRY, this.getParameters(), informationTables, SHOW_TABLES));
643
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_ALL, this.getParameters(), informationTables, SHOW_VIEWS));
644
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_FEATURE, this.getParameters(), informationTables, SHOW_VIEWS));
645
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_GEOMETRY, this.getParameters(), informationTables, SHOW_VIEWS));
646
        }
647
    }
648

    
649
    @Override
650
    public List getDataStoreProviderNames() {
651
        List x = new ArrayList(1);
652
        x.add(this.getProviderName());
653
        return x;
654
    }
655

    
656
    @Override
657
    public void updateTableStatistics(String database, String schema, String table) throws JDBCExecuteSQLException {
658
        UpdateTableStatisticsOperation updateStatistics = this.getOperations().createUpdateTableStatistics(
659
                this.getOperations().createTableReference(database, schema, table, null)
660
        );
661
        updateStatistics.perform();
662
    }
663

    
664
    @Override
665
    public Object execute(String sql) {
666
        ExecuteOperation execute = this.getOperations().createExecute(sql);
667
        return execute.perform();
668
    }
669

    
670
    @Override
671
    public JDBCStoreParameters get(String name) throws DataException {
672
        JDBCStoreParameters params = this.getOpenParameters(name);
673
        return params;
674
    }
675

    
676
    @Override
677
    public SQLBuilder createSQLBuilder() {
678
        JDBCSQLBuilderBase builder = this.getHelper().createSQLBuilder();
679
        return builder;
680
    }
681

    
682
    private CustomResourcesConfig getCustomResourcesConfig() {
683
        JDBCServerExplorerParameters serverParams = this.getParameters();
684
        String key = buildKeyForCachedTables(MODE_ALL, serverParams, false, SHOW_TABLES_AND_VIEWS); //???
685
        CachedValue<CustomResourcesConfig> cachedConfig = CACHED_CUSTOM_RESOURCES_CONFIG.get(key);
686
        if (cachedConfig != null) {
687
//            LOG.info("Get CustomResourcesConfig from CACHE_1: "+!cachedConfig.isExpired());
688
            CustomResourcesConfig config = cachedConfig.get();
689
            return config;
690
        }
691
        JDBCStoreParameters params = this.helper.createOpenStoreParameters(this.getParameters());
692
        cachedConfig = new CachedCustomResourcesConfig(params);
693
        CACHED_CUSTOM_RESOURCES_CONFIG.put(key, cachedConfig);
694
//        LOG.info("Get CustomResourcesConfig from CACHE_2: "+!cachedConfig.isExpired());
695
        return cachedConfig.get();
696
    }
697
    
698
    private void refreshCustomResourcesConfig() {
699
        JDBCServerExplorerParameters serverParams = this.getParameters();
700
        String key = buildKeyForCachedTables(MODE_ALL, serverParams, false, SHOW_TABLES_AND_VIEWS); //???
701
        CachedValue<CustomResourcesConfig> cachedConfig = CACHED_CUSTOM_RESOURCES_CONFIG.get(key);
702
        if (cachedConfig != null) {
703
//            LOG.info("Force expire CustomResourcesConfig cache");
704
            cachedConfig.expired();
705
        }
706
    }
707

    
708
    private ResourcesStorage getResourcesStorage(DataStoreParameters parameters, String storeName) {
709
        if (DatabaseWorkspaceManager.isInternalTable(storeName)) {
710
            EmptyResourcesStorage resourcesStorage = new EmptyResourcesStorage();
711
            return resourcesStorage;
712
        }
713
        String resourcesTablename = null;
714
        try { 
715
            ResourcesStorage alternateResourcesStorage = null;
716
            DataManager dataManager = DALLocator.getDataManager();
717
            DatabaseWorkspaceManager workspace = dataManager.getDatabaseWorkspace(parameters);
718
            if (workspace != null) {
719
                alternateResourcesStorage = workspace.getAlternativeResourcesStorage(storeName);
720
            }
721
            
722
            ResourcesStorage defaultResourcesStorage = null;
723
            ResourcesStorage customResourcesStorage = null;            
724
            
725
            // TODO: Habria que ver de localizar los parametros sin tener que hacer un list.
726
            resourcesTablename = TABLE_RESOURCES_NAME;
727
            List<JDBCStoreParameters> tables = this.list();
728
            for (JDBCStoreParameters params : tables) {
729
                String theTableName = params.getTable();
730
                if (StringUtils.equals(theTableName, resourcesTablename)) {
731
                    defaultResourcesStorage = new JDBCResourcesStorage(
732
                            this.helper,
733
                            alternateResourcesStorage,
734
                            params,
735
                            storeName
736
                    );
737
                    break;
738
                }
739
            }
740
            CustomResourcesConfig config = getCustomResourcesConfig();
741
            if( config!=null ) {
742
                if( config.isInternalTable(storeName) ) {
743
                    defaultResourcesStorage = new EmptyResourcesStorage();
744
                } else {
745
                    resourcesTablename = config.getResourcesTablename(storeName);
746
                    if( StringUtils.isNotBlank(resourcesTablename) ) {
747
                        JDBCStoreParameters params = this.getOpenParameters(resourcesTablename);
748
                        customResourcesStorage = new JDBCResourcesStorage(
749
                                this.helper,
750
                                alternateResourcesStorage,
751
                                params,
752
                                storeName,
753
                                config.isResourcesReadOnly(resourcesTablename)
754
                        );
755
                    }
756
                }
757
            }
758
            return new CompoundResourcesStorage(defaultResourcesStorage, customResourcesStorage);
759
        } catch (Throwable ex) {
760
            LOG.warn("Can't retrieve reources storage for table '" + storeName + "' in '" + this.getParameters().getUrl() + " ("+resourcesTablename+").", ex);
761
        }
762
        EmptyResourcesStorage theResourcesStorage = new EmptyResourcesStorage();
763
        return theResourcesStorage;
764
    }
765

    
766
    @Override
767
    public ResourcesStorage getResourcesStorage() {
768
        JDBCStoreParameters params;
769
        try {
770
            params = this.getOpenParameters(DatabaseWorkspaceManager.TABLE_RESOURCES_NAME);
771
//            params.setTable(DatabaseWorkspaceManager.TABLE_RESOURCES_NAME);
772
            JDBCResourcesStorage theResourcesStorage = new JDBCResourcesStorage(
773
                    this.helper,
774
                    null,
775
                    params,
776
                    TABLENAME_SERVER_EXPLORER_MARK
777
            );
778
            return theResourcesStorage;
779
        } catch (DataException ex) {
780
            return null;
781
        }
782
    }
783

    
784
    @Override
785
    public ResourcesStorage getResourcesStorage(DataStoreParameters parameters) {
786
        if (parameters == null) {
787
            throw new IllegalArgumentException("null is a valid value for parameters.");
788
        }
789
        String tableName;
790
        if (parameters instanceof JDBCNewStoreParameters) {
791
            tableName = ((JDBCNewStoreParameters) parameters).getTable();
792
        } else if (parameters instanceof JDBCStoreParameters) {
793
            tableName = ((JDBCStoreParameters) parameters).getTable();
794
        } else {
795
            throw new IllegalArgumentException("Required a JDBCStoreParameters or JDBCNewStoreParameters parameters, received " + parameters.getClass().getName() + ".");
796
        }
797
        return this.getResourcesStorage(parameters, tableName);
798
    }
799

    
800
    @Override
801
    public ResourcesStorage getResourcesStorage(DataStore dataStore) {
802
        return this.getResourcesStorage((JDBCStoreParameters) dataStore.getParameters(),
803
                dataStore.getName()
804
        );
805
    }
806

    
807
    @Override
808
    public boolean exists(DataStoreParameters parameters) throws DataException {
809
        JDBCStoreParameters params = (JDBCStoreParameters) parameters;
810
        JDBCSQLBuilderBase builder = this.getHelper().createSQLBuilder();
811
        SQLBuilder.TableNameBuilder searchTable = builder.createTableNameBuilder()
812
                .database(params.getDBName())
813
                .schema(params.getSchema())
814
                .name(params.getTable());
815
        SQLBuilder.TableNameBuilder table = builder.createTableNameBuilder();
816

    
817
        List<JDBCStoreParameters> l = this.list();
818
        for (JDBCStoreParameters current : l) {
819
            table.database(current.getDBName())
820
                    .schema(current.getSchema())
821
                    .name(current.getTable());
822
            if (table.equals(searchTable)) {
823
                return true;
824
            }
825
        }
826
        return false;
827
    }
828

    
829
    @Override
830
    public void setCustomResources(String tableName, String resourcesTableName) {
831
        this.setCustomResources(tableName, resourcesTableName, false);
832
    }
833
    
834
    @Override
835
    public void setCustomResources(String tableName, String resourcesTableName, boolean readonly) {
836
        CustomResourcesConfig config = getCustomResourcesConfig();
837
        if( config==null ) {
838
            throw new RuntimeException("Can't retrieve alternative resources configuration");
839
        }
840
        config.addResourceMapping(tableName, resourcesTableName);
841
        config.setResourcesReadOnly(resourcesTableName,readonly);
842
        JDBCStoreParameters params = this.helper.createOpenStoreParameters(this.getParameters());
843
        if(!setConfigValue(params, CONFIG_NAME_CUSTOM_RESOURCES, config.toJsonString())) {
844
            throw new RuntimeException("Can't save custom resources configuration");
845
        }
846
        refreshCustomResourcesConfig();
847
        
848
        
849
        if (StringUtils.isNotBlank(resourcesTableName)) {
850
            try {
851
                params = this.getOpenParameters(resourcesTableName);
852
                JDBCResourcesStorage resourcesStorage = new JDBCResourcesStorage(
853
                        this.helper,
854
                        null,
855
                        params,
856
                        tableName,
857
                        config.isResourcesReadOnly(resourcesTableName)
858
                );
859
                resourcesStorage.clearCache();
860
            } catch (Exception ex) {
861
                LOG.debug("Can't remove local cache for table "+tableName, ex);
862
            }
863
        }
864

    
865

    
866
    }
867

    
868
    private static boolean setConfigValue(JDBCStoreParameters params, String name, String value) {
869
        FeatureStore store = null;
870
        try {
871
            DataManager dataManager = DALLocator.getDataManager();
872
            params.setTable(TABLE_CONFIGURATION_NAME);
873
            store = (FeatureStore) dataManager.openStore(
874
                    params.getProviderName(), 
875
                    params
876
            );
877
        } catch (Exception ex) {
878
            LOG.trace("Can't read configuration value '"+name+"'", ex);
879
            // Do noting
880
//        } finally {
881
//            DisposeUtils.disposeQuietly(store);
882
        }
883
        if( store == null ) {
884
            return false;
885
        }
886
        try {
887
            store.edit();
888
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
889
            String filter = builder.eq(
890
                    builder.column(FIELD_CONFIGURATION_NAME),
891
                    builder.constant(name)
892
            ).toString();
893
            Feature feature = store.findFirst(filter);
894
            EditableFeature efeature;
895
            if (feature == null) {
896
                efeature = store.createNewFeature();
897
                efeature.set(FIELD_CONFIGURATION_NAME, name);
898
                efeature.set(FIELD_CONFIGURATION_VALUE, value);
899
                store.insert(efeature);
900
            } else {
901
                efeature = feature.getEditable();
902
                efeature.set(FIELD_CONFIGURATION_VALUE, value);
903
                store.update(efeature);
904
            }
905
            store.finishEditing();
906
            return true;
907
        } catch (Exception ex) {
908
            LOG.debug("Can't write configuration value for '"+name+"'", ex);
909
            return false;
910
        } finally {
911
            DisposeUtils.disposeQuietly(store);
912
        }
913
    }
914
    
915
//    private static String getConfigValue_useStore(JDBCStoreParameters params, String name) {
916
//        FeatureStore store = null;
917
//        try {
918
//            DataManager dataManager = DALLocator.getDataManager();
919
//            params.setTable(TABLE_CONFIGURATION_NAME);
920
//            store = (FeatureStore) dataManager.openStore(
921
//                    params.getProviderName(), 
922
//                    params
923
//            );
924
//        } catch (Exception ex) {
925
//            LOG.trace("Can't read configuration value '"+name+"'", ex);
926
//            // Do noting
927
////        } finally {
928
////            DisposeUtils.disposeQuietly(store);
929
//        }
930
//        if( store == null ) {
931
//            return null;
932
//        }
933
//        try {
934
//            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
935
//            String filter = builder.eq(
936
//                    builder.column(FIELD_CONFIGURATION_NAME),
937
//                    builder.constant(name)
938
//            ).toString();
939
//            Feature feature = store.findFirst(filter);
940
//            if( feature == null ) {
941
//                return null;
942
//            }
943
//            String value = feature.getString(FIELD_CONFIGURATION_VALUE);
944
//            return value;
945
//        } catch (Exception ex) {
946
//            LOG.debug("Can't read configuration value '"+name+"'", ex);
947
//            return null;
948
//        } finally {
949
//            DisposeUtils.disposeQuietly(store);
950
//        }
951
//    }
952
    
953
    private static String getConfigValue(JDBCStoreParameters params, String name) {
954
        JDBCServerExplorerBase explorer = null;
955
        try {
956
            DataManager dataManager = DALLocator.getDataManager();
957
            params.setTable(TABLE_CONFIGURATION_NAME);
958
            JDBCServerExplorerParameters explorerParams = (JDBCServerExplorerParameters) dataManager.createServerExplorerParameters(params.getProviderName());
959
            ToolsLocator.getDynObjectManager().copy(params, explorerParams);
960
            
961
            explorer = (JDBCServerExplorerBase) dataManager.openServerExplorer(explorerParams.getProviderName(), explorerParams);
962
        
963
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
964
            String filter = builder.eq(
965
                    builder.column(FIELD_CONFIGURATION_NAME),
966
                    builder.constant(name)
967
            ).toString();
968
            OperationsFactory operations = explorer.getOperations();
969
            RetrieveValueOperation op = operations.createRetrieveValue(
970
                    operations.createTableReference(params),
971
                    filter,
972
                    null, //order
973
                    FIELD_CONFIGURATION_VALUE
974
            );
975
            Object value = op.perform();
976
            return Objects.toString(value,null);
977
        } catch (Exception ex) {
978
            LOG.debug("Can't read configuration value '"+name+"'", ex);
979
            return null;
980
        } finally {
981
            DisposeUtils.disposeQuietly(explorer);
982
        }
983
    }
984
    
985
    @Override
986
    public boolean exists() {
987
        try {
988
            JDBCServerExplorerParameters serverParameters = this.getParameters();
989
            OperationsFactory operations = helper.getOperations();
990
            ListTablesOperation listTables = operations.createListTables(
991
                    MODE_ALL, serverParameters, false, SHOW_TABLES
992
            );
993
            List<JDBCStoreParameters> tables = (List<JDBCStoreParameters>) listTables.perform();
994
            return true;
995
        } catch(Throwable th) {
996
            return false;
997
        }
998
    }
999

    
1000
    @Override
1001
    public String getConnectionProviderStatus() {
1002
        return this.helper.getConnectionProviderStatus();
1003
    }
1004

    
1005
    @Override
1006
    public void setTransaction(DataTransaction transaction) {
1007
        if( this.helper!=null ) {
1008
            this.helper.setTransaction((DataTransactionServices) transaction);
1009
        }
1010
    }
1011

    
1012
    @Override
1013
    public DataTransaction getTransaction() {
1014
        if( this.helper==null ) {
1015
            return null;
1016
        }
1017
        return this.helper.getTransaction();
1018
    }
1019

    
1020
    private JDBCStoreParameters getOpenParameters(String tableName) throws DataException {
1021
        //No esta claro si se debe hacer este bucle o no. NO BORRAR ALEGREMENTE
1022
        
1023
//        List<JDBCStoreParameters> tables = this.list();
1024
//        for (JDBCStoreParameters params : tables) {
1025
//            String theTableName = params.getTable();
1026
//            if (StringUtils.equals(theTableName, tableName)) {
1027
//                return params;
1028
//            }
1029
//        }
1030
        JDBCStoreParameters p = this.getOpenParameters();
1031
        p.setTable(tableName);
1032
        return p;
1033
    }
1034
}