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

History | View | Annotate | Download (38.9 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 javax.json.JsonObject;
35
import javax.json.JsonString;
36
import javax.json.JsonValue;
37
import org.apache.commons.codec.binary.Hex;
38
import org.apache.commons.collections.map.LRUMap;
39
import org.apache.commons.lang3.BooleanUtils;
40
import org.apache.commons.lang3.ObjectUtils;
41
import org.apache.commons.lang3.StringUtils;
42
import org.apache.commons.lang3.tuple.ImmutablePair;
43
import org.apache.commons.lang3.tuple.Pair;
44
import org.gvsig.expressionevaluator.ExpressionBuilder;
45
import org.gvsig.expressionevaluator.ExpressionUtils;
46
import org.gvsig.fmap.dal.DALLocator;
47
import org.gvsig.fmap.dal.DataManager;
48
import org.gvsig.fmap.dal.DataStore;
49
import org.gvsig.fmap.dal.DataStoreParameters;
50
import org.gvsig.fmap.dal.DatabaseWorkspaceManager;
51
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_NAME;
52
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_VALUE;
53
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_CONFIGURATION_NAME;
54
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_RESOURCES_NAME;
55
import org.gvsig.fmap.dal.NewDataStoreParameters;
56
import org.gvsig.fmap.dal.SQLBuilder;
57
import org.gvsig.fmap.dal.SQLBuilder.Privilege;
58
import org.gvsig.fmap.dal.exception.CloseException;
59
import org.gvsig.fmap.dal.exception.DataException;
60
import org.gvsig.fmap.dal.exception.InitializeException;
61
import org.gvsig.fmap.dal.exception.OpenException;
62
import org.gvsig.fmap.dal.exception.RemoveException;
63
import org.gvsig.fmap.dal.feature.EditableFeature;
64
import org.gvsig.fmap.dal.feature.EditableFeatureType;
65
import org.gvsig.fmap.dal.feature.Feature;
66
import org.gvsig.fmap.dal.feature.FeatureStore;
67
import org.gvsig.fmap.dal.feature.FeatureType;
68
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
69
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
70
import org.gvsig.fmap.dal.serverexplorer.db.spi.AbstractDBServerExplorer;
71
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemStoreParameters;
72
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
73
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
74
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
75
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
76
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
77
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
78
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecuteSQLException;
79
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
80
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
81
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
82
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CanCreateTablesOperation;
83
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CreateTableOperation;
84
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.DropTableOperation;
85
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.ExecuteOperation;
86
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
87
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.ListTablesOperation;
88
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.UpdateTableStatisticsOperation;
89
import org.gvsig.json.Json;
90
import org.gvsig.json.JsonObjectBuilder;
91
import org.gvsig.tools.dispose.DisposeUtils;
92
import org.gvsig.tools.exception.BaseException;
93
import org.gvsig.tools.resourcesstorage.EmptyResourcesStorage;
94
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
95
import org.gvsig.tools.util.CachedValue;
96
import org.slf4j.Logger;
97
import org.slf4j.LoggerFactory;
98

    
99
@SuppressWarnings("UseSpecificCatch")
100
public class JDBCServerExplorerBase extends AbstractDBServerExplorer implements JDBCServerExplorer {
101

    
102
    private static final Logger LOG = LoggerFactory.getLogger(JDBCServerExplorerBase.class);
103
    private static final String CONFIG_NAME_CUSTOM_RESOURCES = "CUSTOM_RESOURCES";
104

    
105
    protected JDBCHelper helper = null;
106

    
107
    private Boolean canAdd;
108

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

    
112
    private static class CustomResourcesConfig {
113

    
114
        private static final String CUSTOM_RESOURCES_CACHETIME = "CacheTime";
115
        private static final String CUSTOM_RESOURCES_MAPPING = "Mapping";
116
        private static final String CUSTOM_RESOURCES_READONLY = "ResourcesReadonly";
117

    
118

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

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

    
181
        public int getCacheExpireTimeInMillis() {
182
            return cacheTime;
183
        }
184

    
185
        public String getResourcesTablename(String tablename) {
186
            String resourceTablename = mapping.get(tablename);
187
//            LOG.info("Resource of table "+tablename+" = "+resourceTablename);
188
            return resourceTablename;
189
        }
190

    
191
        public void addResourceMapping(String tablename, String resourcesTablename) {
192
            this.mapping.put(tablename, resourcesTablename);
193
        }
194

    
195
        private boolean isInternalTable(String storeName) {
196
            if (DatabaseWorkspaceManager.isInternalTable(storeName)) {
197
                return true;
198
            }
199
            for (String resourcesTablename : this.mapping.values()) {
200
                if( StringUtils.equals(storeName, resourcesTablename) ) {
201
                    return true;
202
                }
203
            }
204
            return false;
205
        }
206

    
207
        public void setResourcesReadOnly(String resourcesTableName, boolean readonly) {
208
            this.resourcesReadonly.put(resourcesTableName,readonly);
209
        }
210
        
211
        public boolean isResourcesReadOnly(String resourcesTableName) {
212
            return this.resourcesReadonly.getOrDefault(resourcesTableName,false);
213
        }
214
    }
215
    
216
    private static class CachedCustomResourcesConfig extends CachedValue<CustomResourcesConfig> {
217

    
218
        private final JDBCStoreParameters openParameters;
219

    
220
        private CachedCustomResourcesConfig(JDBCStoreParameters openParameters) {
221
            this.openParameters = openParameters;
222
            this.setExpireTime(30*60*1000); // 30min
223
        }
224

    
225
        @Override
226
        protected void reload() {
227
            String jsonConfig = getConfigValue(this.openParameters, CONFIG_NAME_CUSTOM_RESOURCES);
228
            CustomResourcesConfig config = new CustomResourcesConfig(jsonConfig);        
229
            this.setExpireTime(config.getCacheExpireTimeInMillis());
230
            this.setValue(config);
231
        }
232
        
233
    }
234

    
235
    private static class CachedTablesValue extends CachedValue<List<JDBCStoreParameters>> {
236

    
237
        private final int mode;
238
        private final JDBCServerExplorerParameters serverParameters;
239
        private final boolean informationTables;
240
        private JDBCHelper helper;
241
        private final int tablesOrViews;
242

    
243
        public CachedTablesValue(JDBCHelper helper, int mode, JDBCServerExplorerParameters serverParameters, boolean informationTables, int tablesOrViews) {
244
            this.mode = mode;
245
            this.serverParameters = serverParameters;
246
            this.informationTables = informationTables;
247
            this.helper = helper;
248
            this.tablesOrViews = tablesOrViews;
249
        }
250

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

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

    
293
    public JDBCServerExplorerBase(
294
            JDBCServerExplorerParameters parameters,
295
            DataServerExplorerProviderServices services,
296
            JDBCHelper helper
297
    ) throws InitializeException {
298
        super(parameters, services);
299
        this.helper = helper;
300
    }
301

    
302
    @Override
303
    public String getProviderName() {
304
        return this.getHelper().getProviderName();
305
    }
306

    
307
    @Override
308
    public String getStoreName() {
309
        return this.getHelper().getProviderName();
310
    }
311

    
312
    protected DataManagerProviderServices getManager() {
313
        return (DataManagerProviderServices) DALLocator.getDataManager();
314
    }
315

    
316
    @Override
317
    public JDBCServerExplorerParameters getParameters() {
318
        return (JDBCServerExplorerParameters) super.getParameters();
319
    }
320

    
321
    @Override
322
    public boolean closeResourceRequested(ResourceProvider resource) {
323
        this.getHelper().getResulSetControler().pack();
324
        return true;
325
    }
326

    
327
    @Override
328
    public void resourceChanged(ResourceProvider resource) {
329
        // Nothing to do
330
    }
331

    
332
    protected JDBCHelper getHelper() {
333
        return helper;
334
    }
335

    
336
    protected OperationsFactory getOperations() {
337
        return this.getHelper().getOperations();
338
    }
339

    
340
    @Override
341
    public DataStore open(DataStoreParameters params) throws DataException {
342
        checkIsMine(params);
343
        DataStore store = super.open(params);
344
        return store;
345
    }
346

    
347
    @Override
348
    public List list(int mode) throws DataException {
349
        return list(mode, SHOW_TABLES_AND_VIEWS);
350
    }
351

    
352
    @Override
353
    public List list(int mode, int tablesOrViews) throws DataException {
354
        boolean informationTables = BooleanUtils.isTrue(
355
                this.getParameters().getShowInformationDBTables()
356
        );
357

    
358
        JDBCServerExplorerParameters serverParams = this.getParameters();
359

    
360
        String key = buildKeyForCachedTables(mode, serverParams, informationTables, tablesOrViews);
361
        CachedValue<List<JDBCStoreParameters>> tablesValue = CACHED_TABLES.get(key);
362
        List<JDBCStoreParameters> tables = null;
363
        if (tablesValue != null) {
364
            tables = tablesValue.get();
365
        }
366
        if (tables != null) {
367
            return tables;
368
        }
369
        tablesValue = new CachedTablesValue(this.helper, mode, serverParams, informationTables, 60000, tablesOrViews); //60"
370
        CACHED_TABLES.put(key, tablesValue);
371
        tables = tablesValue.get();
372
        return tables;
373
    }
374

    
375
    public String buildKeyForCachedTables(int mode, JDBCServerExplorerParameters params, boolean informationTables, int tablesOrViews) {
376
        JDBCServerExplorerParameters clonedParams = (JDBCServerExplorerParameters) params.getCopy();
377
        clonedParams.setSchema(null); //ListTableOperation no usa el schema
378

    
379
        StringBuilder builder = new StringBuilder();
380
        builder.append(String.valueOf(mode));
381
        builder.append(Hex.encodeHex(clonedParams.toByteArray()));
382
        builder.append(String.valueOf(informationTables));
383
        builder.append(String.valueOf(tablesOrViews));
384
        String key = builder.toString();
385
        return key;
386
    }
387

    
388
    @Override
389
    public void remove(DataStoreParameters theParams) throws RemoveException {
390
        JDBCStoreParameters params = (JDBCStoreParameters) theParams;
391
        DropTableOperation removeTable = this.getOperations().createDropTable(
392
                this.getOperations().createTableReference(params)
393
        );
394
        if ((Boolean) removeTable.perform()) {
395
            this.dropCachedTables();
396
        }
397
    }
398

    
399
    @Override
400
    public JDBCStoreParameters getOpenParameters() throws DataException {
401
        JDBCStoreParameters params = this.helper.createOpenStoreParameters(this.getParameters());
402
        return params;
403
    }
404

    
405
    @Override
406
    public NewDataStoreParameters getAddParameters(String storeName)
407
            throws DataException {
408
        JDBCNewStoreParameters params = this.getAddParameters();
409
        params.setTable(storeName);
410
        return params;
411
    }
412

    
413
    @Override
414
    public JDBCNewStoreParameters getAddParameters() throws DataException {
415
        JDBCServerExplorerParameters parameters = getParameters();
416
        JDBCNewStoreParameters params = this.helper.createNewStoreParameters();
417
        params.setHost(parameters.getHost());
418
        params.setPort(parameters.getPort());
419
        params.setDBName(parameters.getDBName());
420
        params.setUser(parameters.getUser());
421
        params.setPassword(parameters.getPassword());
422
        params.setCatalog(parameters.getCatalog());
423
        params.setSchema(parameters.getSchema());
424
        params.setJDBCDriverClassName(parameters.getJDBCDriverClassName());
425
        params.setUrl(parameters.getUrl());
426
        if (parameters instanceof FilesystemStoreParameters) {
427
            File f = ((FilesystemStoreParameters) parameters).getFile();
428
            ((FilesystemStoreParameters) params).setFile(f);
429
        }
430

    
431
        params.setDefaultFeatureType(this.getServerExplorerProviderServices()
432
                .createNewFeatureType());
433

    
434
        return params;
435
    }
436

    
437
    protected void checkIsMine(DataStoreParameters dsp) {
438
        if (!(dsp instanceof JDBCConnectionParameters)) {
439
            throw new IllegalArgumentException(
440
                    "not instance of FilesystemStoreParameters");
441
        }
442
        JDBCServerExplorerParameters parameters = getParameters();
443

    
444
        JDBCConnectionParameters pgp = (JDBCConnectionParameters) dsp;
445
        if (!StringUtils.equals(pgp.getHost(), parameters.getHost())) {
446
            throw new IllegalArgumentException("wrong explorer: Host (mine: "
447
                    + parameters.getHost() + " other:" + pgp.getHost() + ")");
448
        }
449
        if (!ObjectUtils.equals(pgp.getPort(), parameters.getPort())) {
450
            throw new IllegalArgumentException("wrong explorer: Port (mine: "
451
                    + parameters.getPort() + " other:" + pgp.getPort() + ")");
452
        }
453
        if (!StringUtils.equals(pgp.getDBName(), parameters.getDBName())) {
454
            throw new IllegalArgumentException("wrong explorer: DBName (mine: "
455
                    + parameters.getDBName() + " other:" + pgp.getDBName()
456
                    + ")");
457
        }
458
        if (!StringUtils.isEmpty(parameters.getCatalog())) {
459
            if (!StringUtils.equals(pgp.getCatalog(), parameters.getCatalog())) {
460
                throw new IllegalArgumentException(
461
                        "wrong explorer: Catalog (mine: "
462
                        + parameters.getCatalog() + " other:"
463
                        + pgp.getCatalog() + ")");
464
            }
465
        }
466
        if (!StringUtils.isEmpty(parameters.getSchema())) {
467
            if (!StringUtils.equals(pgp.getSchema(), parameters.getSchema())) {
468
                throw new IllegalArgumentException(
469
                        "wrong explorer: Schema (mine: "
470
                        + parameters.getSchema() + " other:"
471
                        + pgp.getSchema() + ")");
472
            }
473
        }
474
    }
475

    
476
    @Override
477
    public void open() throws OpenException {
478

    
479
    }
480

    
481
    @Override
482
    public void close() throws CloseException {
483

    
484
    }
485

    
486
    @Override
487
    protected void doDispose() throws BaseException {
488
        synchronized (CACHED_TABLES) {
489
            List<String> toRemove = new ArrayList<>();
490
            for (Map.Entry<String, CachedValue<List<JDBCStoreParameters>>> entry : CACHED_TABLES.entrySet()) {
491
                CachedTablesValue value = (CachedTablesValue) entry.getValue();
492
                if (value.getHelper() == this.helper) {
493
                    toRemove.add(entry.getKey());
494
                    value.dispose();
495
                }
496
            }
497
            for (String key : toRemove) {
498
                CACHED_TABLES.remove(key);
499
            }
500
            helper.dispose();
501
            helper = null;
502
        }
503
    }
504

    
505
    @Override
506
    public boolean canAdd() {
507
        if (this.canAdd == null) {
508
            CanCreateTablesOperation canAdd_ = this.getOperations().createCanCreateTables();
509
            this.canAdd = (Boolean) canAdd_.perform();
510
        }
511
        return this.canAdd;
512
    }
513

    
514
    @Override
515
    public FeatureType getFeatureType(DataStoreParameters theParams)
516
            throws DataException {
517

    
518
        JDBCStoreParameters params = (JDBCStoreParameters) theParams;
519

    
520
        checkIsMine(params);
521

    
522
        EditableFeatureType fetureType
523
                = this.getServerExplorerProviderServices().createNewFeatureType();
524

    
525
        List<String> primaryKeys = null;
526
        if (params.getPkFields() != null) {
527
            primaryKeys = Arrays.asList(params.getPkFields());
528
        }
529

    
530
        FetchFeatureTypeOperation fetch = this.getOperations().createFetchFeatureType(
531
                fetureType,
532
                this.getOperations().createTableReference(params),
533
                primaryKeys,
534
                params.getDefaultGeometryField(),
535
                params.getCRS()
536
        );
537
        fetch.perform();
538
        return fetureType;
539
    }
540

    
541
    @Override
542
    public boolean add(String providerName, NewDataStoreParameters theParams, boolean overwrite)
543
            throws DataException {
544

    
545
        List<Pair<String, Privilege>> userAndPrivileges = new ArrayList<>();
546
        JDBCNewStoreParameters params = (JDBCNewStoreParameters) theParams;
547
        if (!StringUtils.isEmpty(params.getAllRole())) {
548
            userAndPrivileges.add(
549
                    new ImmutablePair<>(params.getAllRole(), Privilege.ALL)
550
            );
551
        }
552
        if (!StringUtils.isEmpty(params.getDeleteRole())) {
553
            userAndPrivileges.add(
554
                    new ImmutablePair<>(params.getDeleteRole(), Privilege.DELETE)
555
            );
556
        }
557
        if (!StringUtils.isEmpty(params.getInsertRole())) {
558
            userAndPrivileges.add(
559
                    new ImmutablePair<>(params.getInsertRole(), Privilege.INSERT)
560
            );
561
        }
562
        if (!StringUtils.isEmpty(params.getReferenceRole())) {
563
            userAndPrivileges.add(
564
                    new ImmutablePair<>(params.getReferenceRole(), Privilege.REFERENCE)
565
            );
566
        }
567
        if (!StringUtils.isEmpty(params.getSelectRole())) {
568
            userAndPrivileges.add(
569
                    new ImmutablePair<>(params.getSelectRole(), Privilege.SELECT)
570
            );
571
        }
572
        if (!StringUtils.isEmpty(params.getTriggerRole())) {
573
            userAndPrivileges.add(
574
                    new ImmutablePair<>(params.getTriggerRole(), Privilege.TRIGGER)
575
            );
576
        }
577
        if (!StringUtils.isEmpty(params.getTruncateRole())) {
578
            userAndPrivileges.add(
579
                    new ImmutablePair<>(params.getTruncateRole(), Privilege.TRUNCATE)
580
            );
581
        }
582
        if (!StringUtils.isEmpty(params.getUpdateRole())) {
583
            userAndPrivileges.add(
584
                    new ImmutablePair<>(params.getUpdateRole(), Privilege.UPDATE)
585
            );
586
        }
587
        List<String> additionalSQLs = new ArrayList<>();
588
        if (!StringUtils.isEmpty(params.getPostCreatingStatement())) {
589
            additionalSQLs.add(params.getPostCreatingStatement());
590
        }
591
        CreateTableOperation createTable = this.getOperations().createTable(
592
                this.getOperations().createTableReference(params),
593
                params.getDefaultFeatureType(),
594
                userAndPrivileges,
595
                additionalSQLs
596
        );
597

    
598
        boolean isOk = (boolean) createTable.perform();
599
        if (!isOk) {
600
            return false;
601
        }
602

    
603
        // We collect the featureType of the operation because 
604
        // the provider has been able to make changes to it
605
        params.setDefaultFeatureType(createTable.getType());
606

    
607
        if (theParams instanceof NewFeatureStoreParameters) {
608
            DataManager dataManager = DALLocator.getDataManager();
609
            ResourcesStorage resources = this.getResourcesStorage(theParams);
610
            dataManager.writeDALResource(resources, ((NewFeatureStoreParameters) theParams).getDefaultFeatureType());
611
        }
612
        this.dropCachedTables();
613
        return true;
614
    }
615

    
616
    private void dropCachedTables() {
617
        boolean informationTables = BooleanUtils.isTrue(
618
                this.getParameters().getShowInformationDBTables()
619
        );
620
        synchronized(CACHED_TABLES){
621
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_ALL, this.getParameters(), informationTables, SHOW_TABLES_AND_VIEWS));
622
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_FEATURE, this.getParameters(), informationTables, SHOW_TABLES_AND_VIEWS));
623
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_GEOMETRY, this.getParameters(), informationTables, SHOW_TABLES_AND_VIEWS));
624
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_ALL, this.getParameters(), informationTables, SHOW_TABLES));
625
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_FEATURE, this.getParameters(), informationTables, SHOW_TABLES));
626
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_GEOMETRY, this.getParameters(), informationTables, SHOW_TABLES));
627
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_ALL, this.getParameters(), informationTables, SHOW_VIEWS));
628
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_FEATURE, this.getParameters(), informationTables, SHOW_VIEWS));
629
            CACHED_TABLES.remove(buildKeyForCachedTables(MODE_GEOMETRY, this.getParameters(), informationTables, SHOW_VIEWS));
630
        }
631
    }
632

    
633
    @Override
634
    public List getDataStoreProviderNames() {
635
        List x = new ArrayList(1);
636
        x.add(this.getProviderName());
637
        return x;
638
    }
639

    
640
    @Override
641
    public void updateTableStatistics(String database, String schema, String table) throws JDBCExecuteSQLException {
642
        UpdateTableStatisticsOperation updateStatistics = this.getOperations().createUpdateTableStatistics(
643
                this.getOperations().createTableReference(database, schema, table, null)
644
        );
645
        updateStatistics.perform();
646
    }
647

    
648
    @Override
649
    public Object execute(String sql) {
650
        ExecuteOperation execute = this.getOperations().createExecute(sql);
651
        return execute.perform();
652
    }
653

    
654
    @Override
655
    public JDBCStoreParameters get(String name) throws DataException {
656
        JDBCStoreParameters params = this.getOpenParameters();
657
        params.setTable(name);
658
        return params;
659
    }
660

    
661
    @Override
662
    public SQLBuilder createSQLBuilder() {
663
        JDBCSQLBuilderBase builder = this.getHelper().createSQLBuilder();
664
        return builder;
665
    }
666

    
667
    private CustomResourcesConfig getCustomResourcesConfig() {
668
        JDBCServerExplorerParameters serverParams = this.getParameters();
669
        String key = buildKeyForCachedTables(MODE_ALL, serverParams, false, SHOW_TABLES_AND_VIEWS); //???
670
        CachedValue<CustomResourcesConfig> cachedConfig = CACHED_CUSTOM_RESOURCES_CONFIG.get(key);
671
        if (cachedConfig != null) {
672
            CustomResourcesConfig config = cachedConfig.get();
673
//            LOG.info("Return custom resource from CACHE.");
674
            return config;
675
        }
676
        JDBCStoreParameters params = this.helper.createOpenStoreParameters(this.getParameters());
677
        cachedConfig = new CachedCustomResourcesConfig(params);
678
        CACHED_CUSTOM_RESOURCES_CONFIG.put(key, cachedConfig);
679
        return cachedConfig.get();
680
    }
681
    
682
    private void refreshCustomResourcesConfig() {
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
            cachedConfig.expired();
688
        }
689
    }
690

    
691
    private ResourcesStorage getResourcesStorage(DataStoreParameters parameters, String storeName) {
692
        if (DatabaseWorkspaceManager.isInternalTable(storeName)) {
693
            EmptyResourcesStorage resourcesStorage = new EmptyResourcesStorage();
694
            return resourcesStorage;
695
        }
696
        String resourcesTablename = null;
697
        try { 
698
            ResourcesStorage alternateResourcesStorage = null;
699
            DataManager dataManager = DALLocator.getDataManager();
700
            DatabaseWorkspaceManager workspace = dataManager.getDatabaseWorkspace(parameters);
701
            if (workspace != null) {
702
                alternateResourcesStorage = workspace.getAlternativeResourcesStorage(storeName);
703
            }
704
            
705
            ResourcesStorage defaultResourcesStorage = null;
706
            ResourcesStorage customResourcesStorage = null;            
707
            
708
            // TODO: Habria que ver de localizar los parametros sin tener que hacer un list.
709
            resourcesTablename = TABLE_RESOURCES_NAME;
710
            List<JDBCStoreParameters> tables = this.list();
711
            for (JDBCStoreParameters params : tables) {
712
                String theTableName = params.getTable();
713
                if (StringUtils.equals(theTableName, resourcesTablename)) {
714
                    defaultResourcesStorage = new JDBCResourcesStorage(
715
                            alternateResourcesStorage,
716
                            params,
717
                            storeName
718
                    );
719
                    break;
720
                }
721
            }
722
            CustomResourcesConfig config = getCustomResourcesConfig();
723
            if( config!=null ) {
724
                if( config.isInternalTable(storeName) ) {
725
                    defaultResourcesStorage = new EmptyResourcesStorage();
726
                } else {
727
                    resourcesTablename = config.getResourcesTablename(storeName);
728
                    if( StringUtils.isNotBlank(resourcesTablename) ) {
729
                        JDBCStoreParameters params = this.getOpenParameters();
730
                        params.setTable(resourcesTablename);
731
                        customResourcesStorage = new JDBCResourcesStorage(
732
                                alternateResourcesStorage,
733
                                params,
734
                                storeName,
735
                                config.isResourcesReadOnly(resourcesTablename)
736
                        );
737
                    }
738
                }
739
            }
740
            return new CompoundResourcesStorage(defaultResourcesStorage, customResourcesStorage);
741
        } catch (Throwable ex) {
742
            LOG.warn("Can't retrieve reources storage for table '" + storeName + "' in '" + this.getParameters().getUrl() + " ("+resourcesTablename+").", ex);
743
        }
744
        EmptyResourcesStorage theResourcesStorage = new EmptyResourcesStorage();
745
        return theResourcesStorage;
746
    }
747

    
748
    @Override
749
    public ResourcesStorage getResourcesStorage() {
750
        JDBCStoreParameters params;
751
        try {
752
            params = this.getOpenParameters();
753
            params.setTable(DatabaseWorkspaceManager.TABLE_RESOURCES_NAME);
754
            JDBCResourcesStorage theResourcesStorage = new JDBCResourcesStorage(
755
                    null,
756
                    params,
757
                    "$ServerExplorer"
758
            );
759
            return theResourcesStorage;
760
        } catch (DataException ex) {
761
            return null;
762
        }
763
    }
764

    
765
    @Override
766
    public ResourcesStorage getResourcesStorage(DataStoreParameters parameters) {
767
        if (parameters == null) {
768
            throw new IllegalArgumentException("null is a valid value for parameters.");
769
        }
770
        String tableName;
771
        if (parameters instanceof JDBCNewStoreParameters) {
772
            tableName = ((JDBCNewStoreParameters) parameters).getTable();
773
        } else if (parameters instanceof JDBCStoreParameters) {
774
            tableName = ((JDBCStoreParameters) parameters).getTable();
775
        } else {
776
            throw new IllegalArgumentException("Required a JDBCStoreParameters or JDBCNewStoreParameters parameters, received " + parameters.getClass().getName() + ".");
777
        }
778
        return this.getResourcesStorage(parameters, tableName);
779
    }
780

    
781
    @Override
782
    public ResourcesStorage getResourcesStorage(DataStore dataStore) {
783
        return this.getResourcesStorage(
784
                (JDBCStoreParameters) dataStore.getParameters(),
785
                dataStore.getName()
786
        );
787
    }
788

    
789
    @Override
790
    public boolean exists(DataStoreParameters parameters) throws DataException {
791
        JDBCStoreParameters params = (JDBCStoreParameters) parameters;
792
        JDBCSQLBuilderBase builder = this.getHelper().createSQLBuilder();
793
        SQLBuilder.TableNameBuilder searchTable = builder.createTableNameBuilder()
794
                .database(params.getDBName())
795
                .schema(params.getSchema())
796
                .name(params.getTable());
797
        SQLBuilder.TableNameBuilder table = builder.createTableNameBuilder();
798

    
799
        List<JDBCStoreParameters> l = this.list();
800
        for (JDBCStoreParameters current : l) {
801
            table.database(current.getDBName())
802
                    .schema(current.getSchema())
803
                    .name(current.getTable());
804
            if (table.equals(searchTable)) {
805
                return true;
806
            }
807
        }
808
        return false;
809
    }
810

    
811
    @Override
812
    public void setCustomResources(String tableName, String resourcesTableName) {
813
        this.setCustomResources(tableName, resourcesTableName, false);
814
    }
815
    
816
    @Override
817
    public void setCustomResources(String tableName, String resourcesTableName, boolean readonly) {
818
        CustomResourcesConfig config = getCustomResourcesConfig();
819
        if( config==null ) {
820
            throw new RuntimeException("Can't retrieve alternative resources configuration");
821
        }
822
        config.addResourceMapping(tableName, resourcesTableName);
823
        config.setResourcesReadOnly(resourcesTableName,readonly);
824
        JDBCStoreParameters params = this.helper.createOpenStoreParameters(this.getParameters());
825
        if(!setConfigValue(params, CONFIG_NAME_CUSTOM_RESOURCES, config.toJsonString())) {
826
            throw new RuntimeException("Can't save custom resources configuration");
827
        }
828
        refreshCustomResourcesConfig();
829
        
830
        
831
        if (StringUtils.isNotBlank(resourcesTableName)) {
832
            try {
833
                params = this.getOpenParameters();
834
                params.setTable(resourcesTableName);
835
                JDBCResourcesStorage resourcesStorage = new JDBCResourcesStorage(
836
                        null,
837
                        params,
838
                        tableName,
839
                        config.isResourcesReadOnly(resourcesTableName)
840
                );
841
                resourcesStorage.clearCache();
842
            } catch (Exception ex) {
843
                LOG.debug("Can't remove local cache for table "+tableName, ex);
844
            }
845
        }
846

    
847

    
848
    }
849

    
850
    private static boolean setConfigValue(JDBCStoreParameters params, String name, String value) {
851
        FeatureStore store = null;
852
        try {
853
            DataManager dataManager = DALLocator.getDataManager();
854
            params.setTable(TABLE_CONFIGURATION_NAME);
855
            store = (FeatureStore) dataManager.openStore(
856
                    params.getProviderName(), 
857
                    params
858
            );
859
        } catch (Exception ex) {
860
            LOG.trace("Can't read configuration value '"+name+"'", ex);
861
            // Do noting
862
//        } finally {
863
//            DisposeUtils.disposeQuietly(store);
864
        }
865
        if( store == null ) {
866
            return false;
867
        }
868
        try {
869
            store.edit();
870
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
871
            String filter = builder.eq(
872
                    builder.column(FIELD_CONFIGURATION_NAME),
873
                    builder.constant(name)
874
            ).toString();
875
            Feature feature = store.findFirst(filter);
876
            EditableFeature efeature;
877
            if (feature == null) {
878
                efeature = store.createNewFeature();
879
                efeature.set(FIELD_CONFIGURATION_NAME, name);
880
                efeature.set(FIELD_CONFIGURATION_VALUE, value);
881
                store.insert(efeature);
882
            } else {
883
                efeature = feature.getEditable();
884
                efeature.set(FIELD_CONFIGURATION_VALUE, value);
885
                store.update(efeature);
886
            }
887
            store.finishEditing();
888
            return true;
889
        } catch (Exception ex) {
890
            LOG.debug("Can't write configuration value for '"+name+"'", ex);
891
            return false;
892
        } finally {
893
            DisposeUtils.disposeQuietly(store);
894
        }
895
    }
896
    
897
    private static String getConfigValue(JDBCStoreParameters params, String name) {
898
        FeatureStore store = null;
899
        try {
900
            DataManager dataManager = DALLocator.getDataManager();
901
            params.setTable(TABLE_CONFIGURATION_NAME);
902
            store = (FeatureStore) dataManager.openStore(
903
                    params.getProviderName(), 
904
                    params
905
            );
906
        } catch (Exception ex) {
907
            LOG.trace("Can't read configuration value '"+name+"'", ex);
908
            // Do noting
909
//        } finally {
910
//            DisposeUtils.disposeQuietly(store);
911
        }
912
        if( store == null ) {
913
            return null;
914
        }
915
        try {
916
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
917
            String filter = builder.eq(
918
                    builder.column(FIELD_CONFIGURATION_NAME),
919
                    builder.constant(name)
920
            ).toString();
921
            Feature feature = store.findFirst(filter);
922
            if( feature == null ) {
923
                return null;
924
            }
925
            String value = feature.getString(FIELD_CONFIGURATION_VALUE);
926
            return value;
927
            
928
        } catch (Exception ex) {
929
            LOG.debug("Can't read configuration value '"+name+"'", ex);
930
            return null;
931
        } finally {
932
            DisposeUtils.disposeQuietly(store);
933
        }
934
    }
935

    
936
    @Override
937
    public boolean exists() {
938
        try {
939
            JDBCServerExplorerParameters serverParameters = this.getParameters();
940
            OperationsFactory operations = helper.getOperations();
941
            ListTablesOperation listTables = operations.createListTables(
942
                    MODE_ALL, serverParameters, false, SHOW_TABLES
943
            );
944
            List<JDBCStoreParameters> tables = (List<JDBCStoreParameters>) listTables.perform();
945
            return true;
946
        } catch(Throwable th) {
947
            return false;
948
        }
949
    }
950

    
951
    @Override
952
    public String getConnectionProviderStatus() {
953
        return this.helper.getConnectionProviderStatus();
954
    }
955

    
956
    
957
}