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

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

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

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

    
104
    protected JDBCHelper helper = null;
105

    
106
    private Boolean canAdd;
107

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

    
111
    private static class CustomResourcesConfig {
112

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

    
117

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

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

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

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

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

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

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

    
217
        private final JDBCStoreParameters openParameters;
218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
357
        JDBCServerExplorerParameters serverParams = this.getParameters();
358

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

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

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

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

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

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

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

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

    
433
        return params;
434
    }
435

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

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

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

    
478
    }
479

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

    
483
    }
484

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

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

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

    
517
        JDBCStoreParameters params = (JDBCStoreParameters) theParams;
518

    
519
        checkIsMine(params);
520

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
777
    @Override
778
    public ResourcesStorage getResourcesStorage(DataStore dataStore) {
779
        return this.getResourcesStorage(
780
                (JDBCStoreParameters) dataStore.getParameters(),
781
                dataStore.getName()
782
        );
783
    }
784

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

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

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

    
841

    
842
    }
843

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