Statistics
| Revision:

gvsig-projects-pool / org.gvsig.online / trunk / org.gvsig.online / org.gvsig.online.lib / org.gvsig.online.lib.impl / src / main / java / org / gvsig / online / lib / impl / workspace / OnlineWorkspaceImpl.java @ 9515

History | View | Annotate | Download (154 KB)

1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package org.gvsig.online.lib.impl.workspace;
7

    
8
import java.io.File;
9
import java.io.FileInputStream;
10
import java.sql.Timestamp;
11
import java.time.LocalDateTime;
12
import java.time.ZoneOffset;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import javax.json.JsonArray;
23
import javax.json.JsonObject;
24
import javax.json.JsonValue;
25
import org.apache.commons.io.IOUtils;
26
import org.apache.commons.lang3.ArrayUtils;
27
import org.apache.commons.lang3.BooleanUtils;
28
import org.apache.commons.lang3.StringUtils;
29
import org.apache.commons.lang3.mutable.MutableLong;
30
import org.apache.commons.lang3.mutable.MutableObject;
31
import org.cresques.cts.IProjection;
32
import org.gvsig.expressionevaluator.Expression;
33
import org.gvsig.expressionevaluator.ExpressionBuilder;
34
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
35
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
36
import org.gvsig.expressionevaluator.ExpressionUtils;
37
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
38
import org.gvsig.fmap.dal.DALLocator;
39
import org.gvsig.fmap.dal.DataManager;
40
import org.gvsig.fmap.dal.DataServerExplorer;
41
import org.gvsig.fmap.dal.DataServerExplorerParameters;
42
import org.gvsig.fmap.dal.DataStoreParameters;
43
import org.gvsig.fmap.dal.DataTransaction;
44
import org.gvsig.fmap.dal.DatabaseWorkspaceManager;
45
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_NAME;
46
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_VALUE;
47
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_NAME;
48
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_RESOURCE;
49
import org.gvsig.fmap.dal.OpenDataStoreParameters;
50
import org.gvsig.fmap.dal.exception.DataException;
51
import org.gvsig.fmap.dal.feature.DisposableFeatureSetIterable;
52
import org.gvsig.fmap.dal.feature.EditableFeature;
53
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.EditableFeatureType;
55
import org.gvsig.fmap.dal.feature.Feature;
56
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
57
import org.gvsig.fmap.dal.feature.FeatureQuery;
58
import org.gvsig.fmap.dal.feature.FeatureReference;
59
import org.gvsig.fmap.dal.feature.FeatureSet;
60
import org.gvsig.fmap.dal.feature.FeatureStore;
61
import static org.gvsig.fmap.dal.feature.FeatureStore.MODE_FULLEDIT;
62
import static org.gvsig.fmap.dal.feature.FeatureStore.MODE_PASS_THROUGH;
63
import org.gvsig.fmap.dal.feature.FeatureType;
64
import org.gvsig.fmap.dal.feature.OpenFeatureStoreParameters;
65
import org.gvsig.fmap.dal.store.h2.H2SpatialUtils;
66
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
67
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
68
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
69
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
70
import org.gvsig.fmap.geom.Geometry;
71
import org.gvsig.fmap.geom.GeometryException;
72
import org.gvsig.fmap.geom.GeometryLocator;
73
import org.gvsig.fmap.geom.GeometryManager;
74
import org.gvsig.fmap.geom.primitive.Envelope;
75
import org.gvsig.json.Json;
76
import org.gvsig.json.JsonObjectBuilder;
77
import org.gvsig.online.lib.api.OnlineCodeGenerator;
78
import org.gvsig.online.lib.api.OnlineDownloader;
79
import org.gvsig.online.lib.api.OnlineLayer;
80
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANCELLED_BY_USER;
81
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_ADD_CHANGE;
82
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_INSERT_CHANGE;
83
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_OPEN_CHANGES;
84
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_OPEN_ENTITIES;
85
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_REMOVE_CHANGES;
86
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_REMOVE_ENTITY;
87
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_RETRIEVE_ENTITIES;
88
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_REVERT;
89
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_UPDATE;
90
import static org.gvsig.online.lib.api.OnlineManager.ERR_CANT_UPDATE_CLEAN;
91
import static org.gvsig.online.lib.api.OnlineManager.ERR_ENTITY_NOT_EXISTS;
92
import static org.gvsig.online.lib.api.OnlineManager.ERR_INVALID_ENTITY;
93
import static org.gvsig.online.lib.api.OnlineManager.ERR_NO_ERROR;
94
import static org.gvsig.online.lib.api.OnlineManager.ERR_OFFLINE;
95
import static org.gvsig.online.lib.api.OnlineManager.ERR_OK;
96
import static org.gvsig.online.lib.api.OnlineManager.ERR_STORE_NOT_IN_WORKINGCOPY;
97
import static org.gvsig.online.lib.api.OnlineManager.ERR_SYNCHRONIZE;
98
import static org.gvsig.online.lib.api.OnlineManager.ERR_UPDATE_NEED_MERGE;
99
import static org.gvsig.online.lib.api.OnlineManager.FEATURECODE_FIELD_NAME;
100
import static org.gvsig.online.lib.api.OnlineManager.FEATUREVERSION_FIELD_NAME;
101
import static org.gvsig.online.lib.api.OnlineManager.OP_DELETE;
102
import static org.gvsig.online.lib.api.OnlineManager.OP_IGNORE;
103
import static org.gvsig.online.lib.api.OnlineManager.OP_INSERT;
104
import static org.gvsig.online.lib.api.OnlineManager.OP_UNKNOWN;
105
import static org.gvsig.online.lib.api.OnlineManager.OP_UPDATE;
106
import static org.gvsig.online.lib.api.OnlineManager.STATE_CONFLICT;
107
import static org.gvsig.online.lib.api.OnlineManager.STATE_CORRUPT;
108
import static org.gvsig.online.lib.api.OnlineManager.STATE_DISCONNECTED;
109
import static org.gvsig.online.lib.api.OnlineManager.STATE_LOCAL_MODIFIED;
110
import static org.gvsig.online.lib.api.OnlineManager.STATE_LOCAL_NEW;
111
import static org.gvsig.online.lib.api.OnlineManager.STATE_LOCAL_OUTDATED;
112
import static org.gvsig.online.lib.api.OnlineManager.STATE_LOCAL_OUTDATED_AND_MODIFIED;
113
import static org.gvsig.online.lib.api.OnlineManager.STATE_LOCAL_UNMODIFIED;
114
import static org.gvsig.online.lib.api.OnlineManager.STATE_REMOTE_NEW;
115
import static org.gvsig.online.lib.api.OnlineManager.STATE_UNKNOWN;
116
import org.gvsig.online.lib.api.OnlineProject;
117
import org.gvsig.online.lib.api.OnlineRuntimeException;
118
import org.gvsig.online.lib.api.OnlineSite;
119
import org.gvsig.online.lib.api.workingcopy.OnlineEntity;
120
import org.gvsig.online.lib.api.workingcopy.OnlineRemoteChange;
121
import org.gvsig.online.lib.api.workingcopy.OnlineWorkingcopy;
122
import org.gvsig.online.lib.api.workingcopy.OnlineWorkingcopyChange;
123
import org.gvsig.online.lib.api.workingcopy.WorkingArea;
124
import static org.gvsig.online.lib.impl.OnlineManagerImpl.INTERNAL_WORKSPACE_TABLES;
125
import org.gvsig.online.lib.impl.OnlineProjectImpl;
126
import org.gvsig.online.lib.impl.OnlineSiteImpl;
127
import org.gvsig.online.lib.impl.OnlineUtils;
128
import org.gvsig.online.lib.impl.TilesCalculator;
129
import org.gvsig.online.lib.impl.workspace.tables.EntitiesTable;
130
import org.gvsig.online.lib.impl.workspace.tables.EntitiesTable.EntityRow;
131
import org.gvsig.online.lib.impl.workspace.tables.RemoteChangesTable;
132
import org.gvsig.online.lib.impl.workspace.tables.RemoteChangesTable.RemoteChangeRow;
133
import org.gvsig.online.lib.impl.workspace.tables.VarsTable;
134
import org.gvsig.online.lib.impl.workspace.tables.WorkspaceChangesTable;
135
import org.gvsig.online.lib.impl.workspace.tables.WorkspaceChangesTable.WorkspaceChangeRow;
136
import org.gvsig.timesupport.DataTypes;
137
import org.gvsig.tools.ToolsLocator;
138
import org.gvsig.tools.dataTypes.DataTypeUtils;
139
import org.gvsig.tools.dispose.DisposableIterator;
140
import org.gvsig.tools.dispose.DisposeUtils;
141
import org.gvsig.tools.dispose.impl.AbstractDisposable;
142
import static org.gvsig.tools.dynform.spi.DynFormSPIManager.TAG_DYNFORM_READONLY;
143
import org.gvsig.tools.i18n.I18nManager;
144
import org.gvsig.tools.logger.FilteredLogger;
145
import org.gvsig.tools.patch.PatchGenerator;
146
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
147
import org.gvsig.tools.swing.api.ChangeListenerHelper;
148
import org.gvsig.tools.swing.api.ToolsSwingLocator;
149
import org.gvsig.tools.task.SimpleTaskStatus;
150
import org.gvsig.tools.task.UserCancelTaskException;
151
import org.gvsig.tools.util.ChainedIterator;
152
import org.gvsig.tools.util.GetItemWithSize64;
153
import org.gvsig.tools.util.HasAFile;
154
import org.gvsig.tools.util.Rewind;
155
import org.slf4j.Logger;
156
import org.slf4j.LoggerFactory;
157
import org.gvsig.online.lib.api.workingcopy.OnlineChanges;
158

    
159
import static org.gvsig.online.lib.api.OnlineManager.TAG_ONLINE_DATAMODEL;
160
import static org.gvsig.online.lib.api.OnlineManager.TAG_ONLINE_FIELDFORLABEL;
161
import static org.gvsig.online.lib.api.OnlineManager.TAG_ONLINE_LABEL;
162
import org.gvsig.tools.dynobject.Tags;
163
import static org.gvsig.online.lib.api.OnlineManager.ERR_ENTITY_NOT_HAS_FEATURECODE;
164

    
165
/**
166
 *
167
 * @author jjdelcerro
168
 */
169
@SuppressWarnings("UseSpecificCatch")
170
public class OnlineWorkspaceImpl extends AbstractDisposable implements OnlineWorkingcopy {
171

    
172
    private static final Logger LOGGER = LoggerFactory.getLogger(OnlineWorkspaceImpl.class);
173

    
174
    public static final String CONFIG_WORKSPACE_CODE_NAME = "WORKSPACE_CODE";
175
    public static final String CONFIG_WORKSPACE_CODE_CHANGE_ON_FIRST_USE = "CHANGE_ON_FIRST_USE";
176
    public static final String CONFIG_WORKSPACE_LABEL_NAME = "WORKSPACE_LABEL";
177
    public static final String CONFIG_PROJECT_NAME = "PROJECT";
178
//    public static final String CONFIG_USER_NAME = "USER";
179
    public static final String CONFIG_AUTHENTICATIONTOKEN_NAME = "AUTHENTICATIONTOKEN";
180
//    public static final String CONFIG_REPOSITORY_ENTITY_CACHE_TIME_NAME = "REPOSITORY_ENTITY_CACHE_TIME";
181
    public static final String CONFIG_OFFLINE = "OFFLINE";
182
    public static final String CONFIG_ENTITY_LABEL_TEMPLATE = "ENTITY_LABEL_TEMPLATE";
183
    public static final String CONFIG_CURRENT_WORKINGAREA = "CURRENT_WORKINGAREA";
184
//    public static final String CONFIG_USE_SAFE_MODE = "USE_SAFE_MODE";
185

    
186
    private final Map<String, FeatureStore> storesCache;
187
    private Map<String, EntityRow> workspaceEntitiesByName;
188
    private Map<String, EntityRow> workspaceEntitiesByCode;
189
    private Set<FeatureStore> storeIgnoreChanges;
190
    private JDBCServerExplorer wsexplorer;
191
    private String code;
192
    private final OnlineProjectImpl project;
193
    private final String label;
194
    private final FilteredLogger logger;
195
    private final OnlineCodeGenerator codeGenerator;
196
    private final ChangeListenerHelper workspaceEntitiesChangeListeners;
197

    
198
//    private long repositoryEntitiesCacheTime = 30000;
199
    private boolean offline;
200
    private String entityLabelTemplate;
201
    private boolean disposed = false;
202
    private WorkingArea currentWorkingArea;
203

    
204
    public OnlineWorkspaceImpl(JDBCServerExplorer wsexplorer, OnlineCodeGenerator codeGenerator, OnlineProject project, String label) {
205
        // Usado en la inicializacion del workspace
206
        super();
207
        this.logger = new FilteredLogger(LOGGER, "OnlineWorkspace", 10000L);
208
        this.codeGenerator = codeGenerator;
209
        this.storesCache = new HashMap<>();
210
        this.code = createUniqueCode();
211
        this.wsexplorer = wsexplorer;
212
        DisposeUtils.bind(wsexplorer);
213
        this.project = (OnlineProjectImpl) project;
214
        DisposeUtils.bind(this.project);
215
        this.label = label;
216
        this.workspaceEntitiesChangeListeners = ToolsSwingLocator.getToolsSwingManager().createChangeListenerHelper();
217
        this.offline = false;
218
        this.entityLabelTemplate = "${label}";
219
    }
220

    
221
    public OnlineWorkspaceImpl(JDBCServerExplorer wsexplorer, OnlineCodeGenerator codeGenerator, String newLabel) {
222
        // Usado al abrir un workspace ya existente
223
        // Si newLabel no es null cambia la label del workspace.
224
        super();
225
        this.logger = new FilteredLogger(LOGGER, "VCSGisWorkspace", 10000L);
226
        this.codeGenerator = codeGenerator;
227
        this.storesCache = new HashMap<>();
228
        this.wsexplorer = wsexplorer;
229
        DisposeUtils.bind(wsexplorer);
230
        this.workspaceEntitiesChangeListeners = ToolsSwingLocator.getToolsSwingManager().createChangeListenerHelper();
231

    
232
        VarsTable varsTable = new VarsTable();
233
        if( StringUtils.isNotBlank(newLabel) ) {
234
            varsTable.set(this, CONFIG_WORKSPACE_LABEL_NAME, newLabel);
235
        }
236
        
237
        Map<String,String> vars = varsTable.getVars(this, 
238
                CONFIG_PROJECT_NAME,
239
                CONFIG_WORKSPACE_CODE_NAME,
240
//                CONFIG_USER_NAME,
241
                CONFIG_AUTHENTICATIONTOKEN_NAME, 
242
//                CONFIG_REPOSITORY_ENTITY_CACHE_TIME_NAME,
243
                CONFIG_WORKSPACE_LABEL_NAME,
244
                CONFIG_OFFLINE,
245
//                CONFIG_USE_SAFE_MODE,
246
                CONFIG_ENTITY_LABEL_TEMPLATE,
247
                CONFIG_CURRENT_WORKINGAREA
248
        );
249
        this.code = vars.get(CONFIG_WORKSPACE_CODE_NAME);
250
        if (this.code == null) {
251
            throw new RuntimeException("Can't retrieve code from workspace '" + this.getMessageLabel() + "'");
252
        }
253
        if( this.code.equalsIgnoreCase(CONFIG_WORKSPACE_CODE_CHANGE_ON_FIRST_USE) ) {
254
            this.code = this.createUniqueCode();
255
            varsTable.set(this, CONFIG_WORKSPACE_CODE_NAME, this.code);
256
        }
257
        this.offline = DataTypeUtils.toBoolean(vars.get(CONFIG_OFFLINE), false);
258
        this.entityLabelTemplate = vars.getOrDefault(CONFIG_ENTITY_LABEL_TEMPLATE,"${label}");
259
//        this.repositoryEntitiesCacheTime = NumberUtils.toLong(vars.get(CONFIG_REPOSITORY_ENTITY_CACHE_TIME_NAME),30000);
260
        this.reloadWorkspaceEntities();
261
        this.project = (OnlineProjectImpl) Json.toObject(vars.get(CONFIG_PROJECT_NAME));
262
        if (this.project == null) {
263
            throw new RuntimeException("Can't retrieve repository from workspace '" + this.getMessageLabel() + "'");
264
        }
265
        this.currentWorkingArea = (WorkingAreaImpl) Json.toObject(vars.get(CONFIG_CURRENT_WORKINGAREA));
266
        this.label = vars.get(CONFIG_WORKSPACE_LABEL_NAME);
267
        
268
//        this.refreshCodeGeneratorSequence();
269
        
270
//        LOGGER.debug("===: CREATE WORKSPACE "+ hexId(this)+ " (open code='"+this.code+"', label='"+this.label+"')");
271
    }
272

    
273

    
274
    @Override
275
    public String getCode() {
276
        return this.code;
277
    }
278

    
279
    @Override
280
    public String getLabel() {
281
        if (this.disposed) {
282
            return "BROKEN (" + this.label + ")";
283
        }
284
        return this.label;
285
    }
286

    
287
    @Override
288
    public final String createUniqueCode() {
289
        return this.codeGenerator.generateCodeString();
290
    }
291

    
292
    public final long createUniqueCodeLong(String entityName) {
293
        if(!this.codeGenerator.isInitialized(entityName)){
294
            this.refreshCodeGeneratorSequence(entityName);
295
        }
296
        return this.codeGenerator.generateCodelong(entityName);
297
        
298
    }
299

    
300
    @Override
301
    public String getErrorMessage(int errcode) {
302
        return OnlineUtils.getErrorMessage(errcode);
303
    }
304

    
305
    @Override
306
    public JDBCServerExplorer getExplorer() {
307
        return this.wsexplorer;
308
    }
309

    
310
    @Override
311
    public JDBCServerExplorerParameters getExplorerParameters() {
312
        return this.wsexplorer.getParameters();
313
    }
314

    
315
    private String getMessageLabel() {
316
        try {
317
            return this.wsexplorer.getParameters().getUrl();
318
        } catch (Exception ex) {
319
            return "unknown";
320
        }
321
    }
322

    
323
    private String getProviderName() {
324
        return this.wsexplorer.getProviderName();
325
    }
326

    
327
    @Override
328
    public FeatureType getFeatureType(String tableName) {
329
        EntityRow entity = null;
330
        if (!INTERNAL_WORKSPACE_TABLES.contains(tableName)) {
331
            entity = this.getWorkspaceEntityByName(tableName);
332
            if (entity == null) {
333
                return null;
334
            }
335
            return entity.getFeatureType();
336
        }
337
        FeatureType ft = null;
338
        try {
339
            FeatureStore store = this.storesCache.get(tableName);
340
            if (store != null) {
341
                ft = store.getDefaultFeatureType();
342
            } else {
343
                DataManager dataManager = DALLocator.getDataManager();
344
                JDBCStoreParameters params = this.wsexplorer.get(tableName);
345
                store = (FeatureStore) dataManager.openStore(
346
                        getProviderName(),
347
                        params
348
                );
349
                this.storesCache.put(tableName, store);
350
                ft = store.getDefaultFeatureType();
351
            }
352
            return ft;
353
        } catch (Exception ex) {
354
            String msg = "can't open store from '" + this.getMessageLabel() + "'.";
355
            throw new RuntimeException(msg, ex);
356
        }
357
    }
358

    
359
    @Override
360
    public FeatureStore getFeatureStore(String tableName) {
361
        EntityRow entity = null;
362
        if (!INTERNAL_WORKSPACE_TABLES.contains(tableName)) {
363
            entity = this.getWorkspaceEntityByName(tableName);
364
            if (entity == null) {
365
                return null;
366
            }
367
            return getFeatureStore(entity);
368
        }
369
        FeatureStore store = this.storesCache.get(tableName);
370
        if (store != null) {
371
            DisposeUtils.bind(store);
372
            return store;
373
        }
374
        DataManager dataManager = DALLocator.getDataManager();
375
        try {
376
            JDBCStoreParameters params = this.wsexplorer.get(tableName);
377
            store = (FeatureStore) dataManager.openStore(
378
                    getProviderName(),
379
                    params,
380
                    true
381
            );
382
            this.storesCache.put(tableName, store);
383
            DisposeUtils.bind(store);
384
            return store;
385
        } catch (Exception ex) {
386
            LOGGER.trace("can't open store from '" + this.getMessageLabel() + "'.", ex);
387
            return null;
388
        }
389
    }
390

    
391
    private FeatureStore getFeatureStore(OnlineEntity entity) {
392
        FeatureStore store = this.storesCache.get(entity.getEntityName());
393
        if (store != null) {
394
            DisposeUtils.bind(store);
395
            return store;
396
        }
397
        DataManager dataManager = DALLocator.getDataManager();
398
        try {
399
            JDBCStoreParameters params = this.wsexplorer.get(entity.getEntityName());
400
            store = (FeatureStore) dataManager.openStore(
401
                    getProviderName(),
402
                    params
403
            );
404
            StoreProperties.set(store, this, entity.getEntityName());
405
            this.storesCache.put(entity.getEntityName(), store);
406
            DisposeUtils.bind(store);
407
            return store;
408
        } catch (Exception ex) {
409
            LOGGER.trace("can't open store from '" + this.getMessageLabel() + "'.", ex);
410
            return null;
411
        }
412
    }
413

    
414
    public FeatureStore openFeatureStore(OnlineEntity entity) {
415
        DataManager dataManager = DALLocator.getDataManager();
416
        try {
417
            JDBCStoreParameters params = this.wsexplorer.get(entity.getEntityName());
418
            FeatureStore store = (FeatureStore) dataManager.openStore(
419
                    getProviderName(),
420
                    params
421
            );
422
            return store;
423
        } catch (Exception ex) {
424
            LOGGER.trace("can't open store from '" + this.getMessageLabel() + "'.", ex);
425
            return null;
426
        }
427
    }
428

    
429
    @Override
430
    public FeatureStore openFeatureStore(String tableName, boolean ignoreDALResource) {
431
        DataManager dataManager = DALLocator.getDataManager();
432
        try {
433
            JDBCStoreParameters params = this.wsexplorer.get(tableName);
434
            FeatureStore store = (FeatureStore) dataManager.openStore(
435
                    getProviderName(),
436
                    params,
437
                    ignoreDALResource
438
            );
439

    
440
            return store;
441
        } catch (Exception ex) {
442
            LOGGER.trace("can't open store from '" + this.getMessageLabel() + "'.", ex);
443
            return null;
444
        }
445
    }
446

    
447
    @Override
448
    public void forceReloadWorkspaceEntities() {
449
        this.workspaceEntitiesByCode = null;
450
        this.workspaceEntitiesByName = null;
451
    }
452
    
453
    @Override
454
    public void reloadWorkspaceEntities() {
455
        Map<String, EntityRow> localEntities = new HashMap<>();
456
        EntitiesTable entitiesTable = new EntitiesTable();
457
        DisposableFeatureSetIterable allLocalEntities = null;
458
        try {
459
            allLocalEntities = entitiesTable.getAll(this);
460
            for (Feature lentity_f : allLocalEntities) {
461
                EntityRow entityRow = new EntityRow(this, lentity_f);
462
                localEntities.put(entityRow.getEntityName(), entityRow);
463
            }
464
        } catch (Exception ex) {
465
            throw new OnlineRuntimeException(ERR_CANT_RETRIEVE_ENTITIES, OnlineUtils.getErrorMessage(ERR_CANT_RETRIEVE_ENTITIES));
466
        } finally {
467
            DisposeUtils.dispose(allLocalEntities);
468
        }
469

    
470
        reloadWorkspaceEntities(localEntities);
471
    }
472
    
473
    public final void reloadWorkspaceEntities(Map<String,EntityRow> localEntities) {
474
        FeatureStore store = null;
475
        FeatureSet featureSet = null;
476
        try {
477
            Map<String, EntityRow> theEntitiesByName = new HashMap<>();
478
            Map<String, EntityRow> theEntitiesByCode = new HashMap<>();
479
            for (EntityRow entity : localEntities.values()) {
480
                theEntitiesByName.put(entity.getEntityName(), entity);
481
                theEntitiesByCode.put(entity.getCode(), entity);
482
            }
483
            this.workspaceEntitiesByName = theEntitiesByName;
484
            this.workspaceEntitiesByCode = theEntitiesByCode;
485
            this.workspaceEntitiesChangeListeners.fireEvent();
486

    
487
        } catch (Exception ex) {
488
            throw new OnlineRuntimeException(ERR_CANT_RETRIEVE_ENTITIES, OnlineUtils.getErrorMessage(ERR_CANT_RETRIEVE_ENTITIES));
489
        } finally {
490
            DisposeUtils.disposeQuietly(featureSet);
491
            DisposeUtils.disposeQuietly(store);
492
        }
493
    }
494
    
495
//    @Override
496
//    public int add(String name, FeatureStore source, String fieldForLabel) {
497
//        return this.add(name, source, fieldForLabel, null, null, null, null, null, true, null);
498
//    }
499
//
500
//    @Override
501
//    public int add(String name, FeatureStore source, String fieldForLabel, String category, String label) {
502
//        return this.add(name, source, fieldForLabel, category, label, null, null, null, true, null);
503
//    }
504
//
505
//    @Override
506
//    public int add(String name, FeatureStore source, String fieldForLabel, String category, String label, String model, String resources, String pkName, boolean importData, SimpleTaskStatus status) {
507
//        if (isInMyDatabase(source)) {
508
//            return addExistingTable(name, source, fieldForLabel, category, label, model, resources, pkName, status);
509
//        } else {
510
//            return addNewTable(null, name, source, fieldForLabel, category, label, model, resources, pkName, importData, status);
511
//        }
512
//
513
//    }
514
//
515
//    private int addNewTable(String editingSession, String name, FeatureStore source, String fieldForLabel, String category, String label, String model, String resources, String pkName, boolean importData, SimpleTaskStatus status) {
516
//        if (this.getEntity(name) != null) { // is in VCS
517
//            return ERR_ENTITY_ALREADY_EXISTS;
518
//        }
519
//        I18nManager i18n = ToolsLocator.getI18nManager();
520
//        if (status == null) {
521
//            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(i18n.getTranslation("_Add_layer"));
522
//            status.setAutoremove(true);
523
//            status.add();
524
//        } else {
525
//            status.push();
526
//        }
527
//
528
//        FeatureStore target = null;
529
//        FeatureSet srcFeatures = null;
530
//        int errcode = ERR_NO_ERROR;
531
//        DataTransaction transaction = null;
532
//        FeatureStore changesStore = null;
533
//        try {
534
//            transaction = DALLocator.getDataManager().createTransaction();
535
//            transaction.begin();
536
//            LOGGER.debug("===: ADD " + this.getCode() + ", '" + this.getLabel() + "', " + name);
537
//            EntityRow entity = this.getWorkspaceEntityByName(name);
538
//            if (entity != null) {
539
//                return ERR_ENTITY_ALREADY_EXISTS;
540
//            }
541
//            status.message(i18n.getTranslation("_Adding_table_layer"));
542
//            FeatureType ft = source.getDefaultFeatureTypeQuietly();
543
//            errcode = this.addEntity(ft, name, null, fieldForLabel, category, label, model, resources, pkName);
544
//            if (errcode != ERR_NO_ERROR) {
545
//                transaction.rollbackQuietly();
546
//                return errcode;
547
//            }
548
//            errcode = ERR_CANT_OPEN_STORE;
549
//            target = this.openFeatureStore(name,false);
550
//            transaction.add(target);
551
//            errcode = ERR_CANT_RETRIEVE_SOURCE_FEATURES;
552
//            status.message(i18n.getTranslation("_Preparing_source"));
553
//            srcFeatures = source.getFeatureSet();
554
//            transaction.add(srcFeatures);
555
//            errcode = ERR_CANT_INSERT_FEATURES;
556
//            target.edit(MODE_APPEND);
557
//
558
//            changesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME, false);
559
//            transaction.add(changesStore);
560
//            changesStore.edit(MODE_APPEND);
561
//
562
//            this.addStoreIgnoreChanges(target);
563
//            entity = this.getWorkspaceEntityByName(name);
564
//
565
//            if( importData ) {
566
//                status.message(null);
567
//                status.setRangeOfValues(0, srcFeatures.size64());
568
//                status.setCurValue(0);
569
//                for (Feature srcFeature : srcFeatures) {
570
//                    if( status.isCancellationRequested() ) {
571
//                        throw new UserCancelTaskException();
572
//                    }
573
//                    EditableFeature targetFeature;
574
//                    String featureCode = this.createUniqueCode();
575
//                    targetFeature = target.createNewFeature(srcFeature);
576
//                    targetFeature.set(FEATURECODE_FIELD_NAME, featureCode);
577
//                    target.insert(targetFeature);
578
//
579
//                    WorkspaceChangeRow change = new WorkspaceChangeRow(this);
580
//                    change.newCode();
581
//                    change.setEntityCode(entity.getEntityCode());
582
//                    change.setFeatureCode(featureCode);
583
//                    change.setOperation(OP_INSERT);
584
//                    change.setLabel(targetFeature.getString(entity.getFieldForLabel()));
585
//                    change.setSelected(true);
586
//                    change.setStatus(STATE_LOCAL_NEW);
587
//                    change.insert(changesStore);
588
//
589
//                    status.incrementCurrentValue();
590
//                    if (status.isCancellationRequested()) {
591
//                        transaction.rollbackQuietly();
592
//                        status.cancel();
593
//                        return ERR_CANCELLED_BY_USER;
594
//                    }
595
//                }
596
//            }
597
//            status.message(i18n.getTranslation("_Finishing"));
598
//            target.finishEditing();
599
//            transaction.commit();
600
//            this.forceReloadWorkspaceEntities();
601
//            status.terminate();
602
//            return ERR_NO_ERROR;
603
//        } catch (UserCancelTaskException ex) {
604
//            LOGGER.warn("User cancelled");
605
//            status.cancel();
606
//            DataTransaction.rollbackQuietly(transaction);
607
//            throw new UserCancelTaskException();
608
//        } catch (Exception ex) {
609
//            LOGGER.warn("Can't add features to '" + name + "' in '" + this.getMessageLabel() + "'.", ex);
610
//            status.abort();
611
//            DataTransaction.rollbackQuietly(transaction);
612
//            return errcode;
613
//        } finally {
614
//            DisposeUtils.disposeQuietly(transaction);
615
//            DisposeUtils.disposeQuietly(changesStore);
616
//            status.pop();
617
//        }
618
//    }
619
//
620
//    private int addExistingTable(String name, FeatureStore source, String fieldForLabel, String category, String label, String model, String resources, String pkName, SimpleTaskStatus status) {
621
//        if (this.getEntity(name) != null) { // is in working copy
622
//            return ERR_ENTITY_ALREADY_EXISTS;
623
//        }
624
//        DataManager dataManager = DALLocator.getDataManager();
625
//        I18nManager i18n = ToolsLocator.getI18nManager();
626
//        if (status == null) {
627
//            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(i18n.getTranslation("_Add_layer"));
628
//            status.setAutoremove(true);
629
//            status.add();
630
//        } else {
631
//            status.push();
632
//        }
633
//
634
//        FeatureStore target = null;
635
//        FeatureSet targetFeatures = null;
636
//        int errcode = ERR_NO_ERROR;
637
//        DataTransaction transaction = null;
638
//        JDBCServerExplorer explorer = null;
639
//        try {
640
//            explorer = (JDBCServerExplorer) dataManager.openServerExplorer(this.getProviderName(), this.getExplorerParameters());
641
//            transaction = dataManager.createTransaction();
642
//            transaction.begin();
643
//            transaction.add(explorer, false);
644
//            LOGGER.debug("===: ADD " + this.getCode() + ", '" + this.getLabel() + "', " + name);
645
//            EntityRow entity = this.getWorkspaceEntityByName(name);
646
//            if (entity != null) {
647
//                return ERR_ENTITY_ALREADY_EXISTS;
648
//            }
649
//            status.message(i18n.getTranslation("_Adding_table_layer"));
650
//
651
//            FeatureType featureType = source.getDefaultFeatureType();
652
//            FeatureAttributeDescriptor attr = featureType.getAttributeDescriptor(FEATURECODE_FIELD_NAME);
653
//            if (attr == null) {
654
////                explorer.execute("ALTER TABLE \""+name+"\" ADD COLUMN \""+FEATURECODE_FIELD_NAME+"\" VARCHAR(40)");
655
//                explorer.execute(
656
//                        String.format(
657
//                                OnlineUtils.getSqlTemplate(explorer.getProviderName(), "alterTableAddColumnVCSGISCODE"),
658
//                                name
659
//                        )
660
//                );
661
//            }
662
//
663
//            ResourcesStorage resourcesStorage = source.getResourcesStorage();
664
//            if (resourcesStorage != null) {
665
//                ResourcesStorage.Resource resource = resourcesStorage.getResource("dal");
666
//                if (resource != null) {
667
//                    resourcesStorage.remove(resource.getName());
668
//                }
669
//            }
670
//
671
//            target = (FeatureStore) dataManager.openStore(source.getProviderName(), source.getParameters());
672
//            
673
//            
674
//            transaction.add(target);
675
//            errcode = ERR_CANT_RETRIEVE_SOURCE_FEATURES;
676
//            status.message(i18n.getTranslation("_Preparing_source"));
677
//            targetFeatures = target.getFeatureSet();
678
//            transaction.add(targetFeatures);
679
//            errcode = ERR_CANT_INSERT_FEATURES;
680
//            target.edit(MODE_PASS_THROUGH);
681
//
682
//            FeatureStore changesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME,true);
683
//            transaction.add(changesStore);
684
//            changesStore.edit(MODE_APPEND);
685
//
686
//            FeatureStore entitiesStore = this.openFeatureStore(EntitiesTable.TABLE_NAME, true);
687
//            transaction.add(entitiesStore);
688
//            entitiesStore.edit(MODE_FULLEDIT);
689
//
690
//            this.addStoreIgnoreChanges(target);
691
////            entity = this.getWorkspaceEntityByName(name);
692
//            Tags tags = featureType.getTags();
693
//            errcode = ERR_CANT_OPEN_ENTITIES;
694
//            entity = new EntityRow(this);
695
//            entity.newCode();
696
//            entity.setEntityName(name);
697
//            entity.setFeatureIdFieldName(FEATURECODE_FIELD_NAME);
698
//            entity.setGeometryFieldName(featureType.getDefaultGeometryAttributeName());
699
//            entity.setDescription(null);
700
//            entity.setFieldForLabel(StringUtils.equalsIgnoreCase(fieldForLabel, AUTODETECT_FLAG)? tags.getString(TAG_ONLINE_FIELDFORLABEL, null) : fieldForLabel);
701
//            entity.setFeatureTypeAsJson(featureType.toJsonBuilder().toString());
702
//            entity.setState(STATE_LOCAL_NEW);
703
//            entity.setDataModels(StringUtils.equalsIgnoreCase(model, AUTODETECT_FLAG)? tags.getString(TAG_ONLINE_DATAMODEL, null) : model);
704
//            entity.setLabel(StringUtils.equalsIgnoreCase(label, AUTODETECT_FLAG)? tags.getString(TAG_ONLINE_LABEL, null) : label);
705
//            entity.insert(entitiesStore);
706
//            entitiesStore.finishEditing();
707
//
708
//            addWorkspaceEntity(entity);
709
//            
710
//            errcode = ERR_CANT_INSERT_CHANGE;
711
//
712
////            entity = this.getWorkspaceEntityByName(name);
713
//
714
////            addChange(entity, OP_ADD_ENTITY, changesStore, null, null);
715
//            WorkspaceChangeRow change = new WorkspaceChangeRow(this);
716
//            change.newCode();
717
//            change.setEntityCode(entity.getCode());
718
//            change.setFeatureCode(null);
719
//            change.setOperation(OP_ADD_ENTITY);
720
//            change.setSelected(true);
721
//            change.insert(changesStore);
722
//
723
//            status.message(null);
724
//            status.setRangeOfValues(0, targetFeatures.size64());
725
//            status.setCurValue(0);
726
//            for (Feature targetFeature : targetFeatures) {
727
//                if( status.isCancellationRequested() ) {
728
//                    throw new UserCancelTaskException();
729
//                }
730
//                EditableFeature editableFeature;
731
//                String featureCode = this.createUniqueCode();
732
//
733
//                editableFeature = targetFeature.getEditable();
734
//                editableFeature.set(FEATURECODE_FIELD_NAME, featureCode);
735
//                targetFeatures.update(editableFeature);
736
//
737
//                change = new WorkspaceChangeRow(this);
738
//                change.newCode();
739
//                change.setEntityCode(entity.getEntityCode());
740
//                change.setFeatureCode(featureCode);
741
//                change.setOperation(OP_INSERT);
742
//                change.setLabel(editableFeature.getString(entity.getFieldForLabel()));
743
//                change.setSelected(true);
744
//                change.setStatus(STATE_LOCAL_NEW);
745
//                change.insert(changesStore);
746
//
747
//                status.incrementCurrentValue();
748
//                if (status.isCancellationRequested()) {
749
//                    transaction.rollbackQuietly();
750
//                    status.cancel();
751
//                    return ERR_CANCELLED_BY_USER;
752
//                }
753
//            }
754
//
755
//            target.finishEditing();
756
//
757
//            status.message(i18n.getTranslation("_Finishing"));
758
//            transaction.commit();
759
//            this.forceReloadWorkspaceEntities();
760
//            
761
//            transaction.remove(explorer);
762
//
763
////            explorer.execute("ALTER TABLE \""+name+"\" DROP PRIMARY KEY");
764
//            explorer.execute(
765
//                    String.format(
766
//                            OnlineUtils.getSqlTemplate(explorer.getProviderName(), "alterTableDropPrimaryKey"),
767
//                            entity.getEntityName()
768
//                    )
769
//            );
770
//
771
////            explorer.execute("ALTER TABLE \""+name+"\" ALTER COLUMN \""+FEATURECODE_FIELD_NAME+"\" SET NOT NULL");
772
//            explorer.execute(
773
//                    String.format(
774
//                            OnlineUtils.getSqlTemplate(explorer.getProviderName(), "alterTableAlterColumnVCSGISCODESetNotNull"),
775
//                            entity.getEntityName()
776
//                    )
777
//            );
778
//
779
////            explorer.execute("ALTER TABLE \""+name+"\" ADD PRIMARY KEY (\""+FEATURECODE_FIELD_NAME+"\")");
780
//            explorer.execute(
781
//                    String.format(
782
//                            OnlineUtils.getSqlTemplate(explorer.getProviderName(), "alterTableAddPrimaryKeyVCSGISCODE"),
783
//                            entity.getEntityName()
784
//                    )
785
//            );
786
//
787
//            resourcesStorage = target.getResourcesStorage();
788
//            if (resourcesStorage != null) {
789
//                ResourcesStorage.Resource resource = resourcesStorage.getResource("dal");
790
//                if (resource != null) {
791
//                    resourcesStorage.remove(resource.getName());
792
//                }
793
//            }
794
//
795
//            target = (FeatureStore) dataManager.openStore(source.getProviderName(), source.getParameters());
796
//            target.edit();
797
//            EditableFeatureType ft = target.getDefaultFeatureTypeQuietly().getEditable();
798
//            EditableFeatureAttributeDescriptor geomattr = (EditableFeatureAttributeDescriptor) ft.getDefaultGeometryAttribute();
799
//            if( geomattr!=null ) {
800
//                geomattr.setIsIndexed(true);
801
//            }
802
//            EditableFeatureAttributeDescriptor eattr = ft.getEditableAttributeDescriptor(FEATURECODE_FIELD_NAME);
803
//            eattr.getTags().set(TAG_DYNFORM_READONLY, true);
804
//            target.update(ft);
805
//            target.finishEditing();
806
//
807
//            entitiesStore.edit(MODE_FULLEDIT);
808
//            entity.setFeatureTypeAsJson(ft.toJsonBuilder().toString());
809
//            entity.update(entitiesStore);
810
//            entitiesStore.finishEditing();
811
//
812
//            this.forceReloadWorkspaceEntities();
813
//            
814
//            status.terminate();
815
//            return ERR_NO_ERROR;
816
//        } catch (UserCancelTaskException ex) {
817
//            LOGGER.warn("User cancelled");
818
//            status.cancel();
819
//            DataTransaction.rollbackQuietly(transaction);
820
//            throw new UserCancelTaskException();
821
//        } catch (Exception ex) {
822
//            LOGGER.warn("Can't add features to '" + name + "' in '" + this.getMessageLabel() + "'.", ex);
823
//            status.abort();
824
//            DataTransaction.rollbackQuietly(transaction);
825
//            return errcode;
826
//        } finally {
827
//            DisposeUtils.disposeQuietly(transaction);
828
//            DisposeUtils.disposeQuietly(explorer);
829
//            status.pop();
830
//        }
831
//    }
832
//    public int addEntity(FeatureType featureType, String name, String description, String fieldForLabel) {
833
//        return this.addEntity(featureType, name, description, fieldForLabel, null, null, null, null, null);
834
//    }
835
    public int addEntity(FeatureType featureType, String name, String description, String fieldForLabel, String label, String pkName, int tileSize) {
836
        FeatureStore store = null;
837
        int err = ERR_NO_ERROR;
838
        try {
839
            LOGGER.debug("===: ADD_ENTITY " + this.getCode() + ", '" + this.getLabel() + "', " + name);
840
            EditableFeatureType ft = featureType.getCopy().getEditable();
841

    
842
            for (FeatureAttributeDescriptor attr : ft.getPrimaryKey()) {
843
                EditableFeatureAttributeDescriptor editAttr = (EditableFeatureAttributeDescriptor) attr;
844
                editAttr.setIsPrimaryKey(false);
845
                editAttr.setAllowNull(false);
846
                editAttr.setIsIndexed(true);
847
                editAttr.setAllowIndexDuplicateds(false);
848
            }
849

    
850
            EditableFeatureAttributeDescriptor attr = (EditableFeatureAttributeDescriptor) ft.getAttributeDescriptor(FEATURECODE_FIELD_NAME);
851
            if (attr == null) {
852
                err = ERR_ENTITY_NOT_HAS_FEATURECODE;
853
                attr = (EditableFeatureAttributeDescriptor) ft.add(FEATURECODE_FIELD_NAME, DataTypes.LONG)
854
//                        .setSize(ONLINECODELEN)
855
                        .setIsPrimaryKey(true)
856
                        .setIsIndexed(true)
857
                        .setAllowIndexDuplicateds(false)
858
                        .setLabel("Online Code");
859
                ft.setHasOID(false);
860
            } else {
861
                if (!attr.isPrimaryKey()) {
862
                    attr.setIsPrimaryKey(true);
863
                    ft.setHasOID(false);
864
                }
865
            }
866
            attr.getTags().set(TAG_DYNFORM_READONLY, true);
867

    
868
            EditableFeatureAttributeDescriptor geomattr = (EditableFeatureAttributeDescriptor) ft.getDefaultGeometryAttribute();
869
            if (geomattr != null) {
870
                geomattr.setIsIndexed(true);
871
            }
872

    
873
            featureType = ft.getNotEditableCopy();
874
            String defaultFieldForLabel = null;
875
            FeatureAttributeDescriptor[] pk = featureType.getPrimaryKey();
876
            if (pk == null || pk.length < 1) {
877
                defaultFieldForLabel = featureType.getAttributeName(0);
878
            } else {
879
                defaultFieldForLabel = pk[0].getName();
880
            }
881

    
882
            err = ERR_CANT_OPEN_ENTITIES;
883
            Tags tags = featureType.getTags();
884
            EntityRow entity = new EntityRow(this);
885
            entity.newCode();
886
            entity.setEntityName(name);
887
            entity.setFeatureIdFieldName(FEATURECODE_FIELD_NAME);
888
            entity.setGeometryFieldName(featureType.getDefaultGeometryAttributeName());
889
            entity.setDescription(description);
890
            entity.setFieldForLabel(StringUtils.equalsIgnoreCase(fieldForLabel, AUTODETECT_FLAG) ? tags.getString(TAG_ONLINE_FIELDFORLABEL, defaultFieldForLabel) : fieldForLabel);
891
            entity.setFeatureTypeAsJson(featureType.toJsonBuilder().toString());
892
            entity.setDataModels(tags.getString(TAG_ONLINE_DATAMODEL, null));
893
            entity.setLabel(StringUtils.equalsIgnoreCase(label, AUTODETECT_FLAG) ? tags.getString(TAG_ONLINE_LABEL, null) : label);
894
            entity.setTileSize(tileSize);
895
            if (geomattr != null) {
896
                IProjection crs = geomattr.getSRS();
897
                if (crs != null) {
898
                    entity.setCRS(crs);
899
                }
900
            }
901
            entity.setState(STATE_LOCAL_UNMODIFIED);
902
            entity.insert();
903
            addWorkspaceEntity(entity);
904

    
905
            this.forceReloadWorkspaceEntities();
906
            err = ERR_CANT_INSERT_CHANGE;
907

    
908
//            WorkspaceChangeRow change = new WorkspaceChangeRow(this);
909
//            change.newCode();
910
//            change.setEditingSession(null);
911
//            change.setEntityCode(entity.getCode());
912
//            change.setFeatureCode(0);
913
//            change.setOperation(OP_ADD_ENTITY);
914
//            change.setSelected(true);
915
//            change.insert();
916

    
917
            this.create_table(entity);
918
//            store = this.openFeatureStore(entity);
919
//            this.addStoreIgnoreChanges(store);
920
            
921
        } catch (OnlineRuntimeException ex) {
922
            LOGGER.warn("can't add entity '" + name + "'.", ex);
923
            if (store != null) {
924
                store.cancelEditingQuietly();
925
            }
926
            return ex.getErrnum();
927
        } catch (Exception ex) {
928
            LOGGER.warn("can't add entity '" + name + "'.", ex);
929
            if (store != null) {
930
                store.cancelEditingQuietly();
931
            }
932
            return err;
933
        } finally {
934
            DisposeUtils.disposeQuietly(store);
935
        }
936
        return ERR_NO_ERROR;
937
    }
938

    
939
    @Override
940
    public void create_table(String name) {
941
        EntityRow entity = this.getWorkspaceEntityByName(name);
942
        if (entity == null) {
943
            throw new IllegalArgumentException("Can't locate informacion of table '" + name + "'.");
944
        }
945
        create_table(entity);
946
    }
947

    
948
    @Override
949
    public void create_table(OnlineEntity entity) {
950
        create_table(entity, entity.getEntityName());
951
    }
952

    
953
    public void create_table(OnlineEntity entity, String tableName) {
954
        if (entity == null) {
955
            throw new IllegalArgumentException("Entity is null.");
956
        }
957
        try {
958
//            DataManager dataManager = DALLocator.getDataManager();
959
            JDBCNewStoreParameters addparams = (JDBCNewStoreParameters) this.wsexplorer.getAddParameters(tableName);
960
            addparams.setDefaultFeatureType(entity.getFeatureType());
961
            this.wsexplorer.add(getProviderName(), addparams, true);
962

    
963
        } catch (Exception ex) {
964
            throw new RuntimeException("Can't create table '" + entity.getEntityName() + "'.", ex);
965
        }
966

    
967
    }
968

    
969
    public int addChanges(FeatureStore store, String editingSession, Iterator<Feature> insertedsFeatures, Iterator<Feature> updatedsFeatures, Iterator<FeatureReference> deletedsFeatures, Iterator<FeatureType.FeatureTypeChanged> changedsFeatureTypes) {
970
        String entityName = StoreProperties.getEntityName(store);
971
        if (StringUtils.isBlank(entityName)) {
972
            return ERR_STORE_NOT_IN_WORKINGCOPY;
973
        }
974
        if (this.isInStoreIgnoreChanges(store)) {
975
            LOGGER.debug("===: ADD_CHANGE: Skip (" + store.getName() + ")");
976
            return ERR_NO_ERROR;
977
        }
978
        EntityRow entity = this.getWorkspaceEntityByName(entityName);
979
        if (entity == null) {
980
            return ERR_STORE_NOT_IN_WORKINGCOPY;
981
        }
982
        if (entity.getState() == STATE_DISCONNECTED) {
983
            return ERR_OK;
984
        }
985
        if (this.isCorrupt(entity, store, 0)) {
986
            return ERR_OK;
987
        }
988
//        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
989
        FeatureStore workspaceChangesStore = null;
990
        int err = ERR_CANT_OPEN_CHANGES;
991
        try {
992
            workspaceChangesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME, false);
993
            err = ERR_CANT_INSERT_CHANGE;
994
            Map<Long, Integer> previousOperations = null;
995
            if (updatedsFeatures instanceof Rewind && insertedsFeatures instanceof Rewind) {
996
                previousOperations = calculatePreviousOperations(entity, workspaceChangesStore, insertedsFeatures, updatedsFeatures);
997
                workspaceChangesStore.edit(FeatureStore.MODE_APPEND);
998
            } else {
999
                workspaceChangesStore.edit(FeatureStore.MODE_PASS_THROUGH);
1000
            }
1001
            if (insertedsFeatures != null) {
1002
                while (insertedsFeatures.hasNext()) {
1003
                    Feature f = insertedsFeatures.next();
1004
                    if (f == null) {
1005
                        continue;
1006
                    }
1007
//                    if( this.useSafeMode() ) {
1008
//                        // Estamos antes de terminar edicion, la feature f aun no se ha insertado.
1009
//                        long featurecode = f.getLong(FEATURECODE_FIELD_NAME);
1010
//                        Feature fuser = store.findFirst("\"+FEATURECODE_FIELD_NAME+\" = '"+featurecode+"'");
1011
//                        if( fuser!=null ) {
1012
//                            err = ERR_CANT_INSERT_CHANGE;
1013
//                            throw new RuntimeException("Feature already exists for vcsgiscode = '"+featurecode+"'");
1014
//                        }
1015
//                    }
1016
                    addChange(editingSession, entity, OP_INSERT, workspaceChangesStore, f, null, previousOperations);
1017
                }
1018
            }
1019
            if (updatedsFeatures != null) {
1020
                while (updatedsFeatures.hasNext()) {
1021
                    Feature f = updatedsFeatures.next();
1022
                    if (f == null) {
1023
                        continue;
1024
                    }
1025
                    Feature originalFeature = store.getOriginalFeature(f);
1026
//                    if( this.useSafeMode() ) {
1027
//                        // Estamos antes de terminar edicion, la feature f aun no se ha insertado.
1028
//                        long featurecode = f.getLong(FEATURECODE_FIELD_NAME);
1029
//                        Feature fuser = store.findFirst("\"+FEATURECODE_FIELD_NAME+\" = '"+featurecode+"'");
1030
//                        if( fuser!=null ) {
1031
//                            err = ERR_CANT_INSERT_CHANGE;
1032
//                            throw new RuntimeException("Feature already exists for vcsgiscode = '"+featurecode+"'");
1033
//                        }
1034
//                    }                    
1035
                    addChange(editingSession, entity, OP_UPDATE, workspaceChangesStore, f, originalFeature, previousOperations);
1036
                }
1037
            }
1038
            if (previousOperations != null) {
1039
                workspaceChangesStore.finishEditing();
1040
                workspaceChangesStore.edit(FeatureStore.MODE_PASS_THROUGH);
1041
            }
1042
            if (deletedsFeatures != null) {
1043
                while (deletedsFeatures.hasNext()) {
1044
                    FeatureReference fr = deletedsFeatures.next();
1045
                    if (fr == null) {
1046
                        continue;
1047
                    }
1048
                    Feature f = fr.getFeatureQuietly();
1049
                    if (f == null) {
1050
                        continue;
1051
                    }
1052
                    Feature originalFeature = store.getOriginalFeature(fr);
1053
//                    if( this.useSafeMode() ) {
1054
//                        // Estamos antes de terminar edicion, la feature f aun no se ha insertado.
1055
//                        long featurecode = f.getLong(FEATURECODE_FIELD_NAME);
1056
//                        Feature fuser = store.findFirst("\"+FEATURECODE_FIELD_NAME+\" = '"+featurecode+"'");
1057
//                        if( fuser!=null ) {
1058
//                            err = ERR_CANT_INSERT_CHANGE;
1059
//                            throw new RuntimeException("Feature already exists for vcsgiscode = '"+featurecode+"'");
1060
//                        }
1061
//                    }
1062
                    addDeleteChange(editingSession, entity, workspaceChangesStore, f.getLong(entity.getFeatureIdFieldName()), f.getString(entity.getFieldForLabel()), originalFeature);
1063
                }
1064
            }
1065
            workspaceChangesStore.finishEditing();
1066

    
1067
            if (changedsFeatureTypes != null && changedsFeatureTypes.hasNext()) {
1068
                try {
1069
                    entity.setState(STATE_DISCONNECTED);
1070
                    entity.update();
1071
                } catch (Throwable t) {
1072
                    LOGGER.warn("Can't update entity state");
1073
                }
1074
            }
1075

    
1076
            err = ERR_NO_ERROR;
1077
        } catch (Exception ex) {
1078
            LOGGER.warn("Can't add changes.", ex);
1079
            if (workspaceChangesStore != null) {
1080
                workspaceChangesStore.cancelEditingQuietly();
1081
            }
1082
        } finally {
1083
            DisposeUtils.disposeQuietly(workspaceChangesStore);
1084
        }
1085
        return err;
1086
    }
1087
    
1088
    public int addChange(String editingSession, int operation, FeatureStore userStore, Feature feature) {
1089
        String entityName = StoreProperties.getEntityName(userStore);
1090
        if (StringUtils.isBlank(entityName)) {
1091
            return ERR_STORE_NOT_IN_WORKINGCOPY;
1092
        }
1093
        if (this.isInStoreIgnoreChanges(userStore)) {
1094
            LOGGER.debug("===: ADD_CHANGE: Skip (" + userStore.getName() + ")");
1095
            return ERR_NO_ERROR;
1096
        }
1097
        boolean isUserStoreInAppendMode = userStore.getMode()==FeatureStore.MODE_APPEND;
1098
        EntityRow entity = (EntityRow) this.getWorkspaceEntityByName(entityName);
1099
        if( entity.getState()==STATE_DISCONNECTED ) {
1100
            return ERR_OK;
1101
        }
1102
        FeatureStore changesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME,false);
1103
        try {
1104
            changesStore.edit(MODE_PASS_THROUGH);
1105
            long featureCode = feature.getLong(entity.getFeatureIdFieldName());
1106
            switch(operation) {
1107
            case OP_DELETE:
1108
                String label = feature.getString(entity.getFieldForLabel());
1109
//               if( this.useSafeMode() && !isUserStoreInAppendMode ) {
1110
//                    Feature fuser = userStore.findFirst("VCSGISCODE = '"+featureCode+"'");
1111
//                    if( fuser==null ) {
1112
//                        throw new RuntimeException("Can't get original feature for deleted vcsgiscode = '"+featureCode+"'");
1113
//                    }
1114
//                }                
1115
                return addDeleteChange(editingSession, entity, changesStore, featureCode, label, userStore.getOriginalFeature(feature));
1116
            case OP_INSERT:
1117
//               if( this.useSafeMode() && !isUserStoreInAppendMode ) {
1118
//                    Feature fuser = userStore.findFirst("VCSGISCODE = '"+featureCode+"'");
1119
//                    if( fuser!=null ) {
1120
//                        throw new RuntimeException("Already exists feature with vcsgiscode = '"+featureCode+"'");
1121
//                    }
1122
//                }                
1123
                return addChange(editingSession, entity, operation, changesStore, feature, userStore.getOriginalFeature(feature), null);
1124
            case OP_UPDATE:
1125
//               if( this.useSafeMode() && !isUserStoreInAppendMode ) {
1126
//                    Feature fuser = userStore.findFirst("VCSGISCODE = '"+featureCode+"'");
1127
//                    if( fuser==null ) {
1128
//                        throw new RuntimeException("Can't get original feature for update vcsgiscode = '"+featureCode+"'");
1129
//                    }
1130
//                }                
1131
                return addChange(editingSession, entity, operation, changesStore, feature, userStore.getOriginalFeature(feature), null);
1132
            default:
1133
                LOGGER.warn("Unsupported operation "+operation+".");
1134
                return addChange(editingSession, entity, operation, changesStore, feature, userStore.getOriginalFeature(feature), null);
1135
            }
1136
        } catch (Exception ex) {
1137
            LOGGER.warn("Can't add change (op " + OnlineUtils.getOperationLabel(operation) + ", " + entity.getEntityName() + ")", ex);
1138
            changesStore.cancelEditingQuietly();
1139
            return ERR_CANT_ADD_CHANGE;
1140
        } finally {
1141
            changesStore.finishEditingQuietly();
1142
            DisposeUtils.dispose(changesStore);
1143
        }
1144
    }
1145

    
1146

    
1147

    
1148
    private int addChange(String editingSession, EntityRow entity, int operation, FeatureStore changesStore, Feature feature, Feature oldFeature, Map<Long, Integer> previousOperations) {
1149
        if (entity.getState() == STATE_DISCONNECTED) {
1150
            return ERR_OK;
1151
        }
1152
        if (operation == OP_DELETE) {
1153
            // Por aqui no deberia pasar de normal. 
1154
            // Si esta en MODE_FULLEDIT no deberia pasar.
1155
            // En MODE_PASSTH... el otro metodo addChange deberia haberlo atrapado,
1156
            // y derivado al addDeleteChange. 
1157
            // Por si acaso llega aqui, lo derivamos al addDeleteChange.
1158
            long featureCode = feature.getLong(entity.getFeatureIdFieldName());
1159
            String label = feature.getString(entity.getFieldForLabel());
1160
            return addDeleteChange(editingSession, entity, changesStore, featureCode, label, oldFeature);
1161
        }
1162
        if (oldFeature == null) {
1163
            if (feature instanceof EditableFeature) {
1164
                oldFeature = ((EditableFeature) feature).getSource();
1165
            }
1166
        }
1167
        try {
1168
            Feature previousChange = null;
1169
            long featureCode = feature.getLong(entity.getFeatureIdFieldName());
1170
            Integer previousOperation = null;
1171
            if (previousOperations != null) {
1172
                previousOperation = previousOperations.get(featureCode);
1173
            } else {
1174
                previousChange = changesStore.findFirst(WorkspaceChangesTable.FEATUREID + " = '" + featureCode + "'"); // and " + WorkspaceChangesTable.OPERATION+ " = " + operation);
1175
                if (previousChange != null) {
1176
                    previousOperation = previousChange.getInt(WorkspaceChangesTable.OPERATION);
1177
                }
1178
            }
1179
            if (previousOperation != null) {
1180
                /*
1181
                operation - previo
1182
                INS - INS -> Error
1183
                INS - UPD -> Error
1184
                INS - DEL -> Error
1185
                UPD - INS -> no hace nada y sale con OK
1186
                UPD - UPD -> no hace nada y sale con OK
1187
                UPD - DEL -> Error
1188
                DEL - INS -> Error, aqui no deberia llegar un DEL
1189
                DEL - UPD -> Error, aqui no deberia llegar un DEL
1190
                DEL - DEL -> Error, aqui no deberia llegar un DEL
1191
                 */
1192
                switch (operation) {
1193
                    case OP_INSERT:
1194
                        LOGGER.warn("A insert change cannot be added as there is a previous change with operation " + previousOperation + " (featureCode=" + featureCode + ")");
1195
                        return ERR_CANT_ADD_CHANGE;
1196
                    case OP_UPDATE:
1197
                        switch (previousOperation) {
1198
                            case OP_INSERT:
1199
                            case OP_UPDATE:
1200
                                //TODO: Migrar a VCSGIS
1201
                                if(previousChange != null ) {
1202
                                    WorkspaceChangeRow change = new WorkspaceChangeRow(this, previousChange);
1203
                                    if(change.getStatus() == STATE_CONFLICT){
1204
                                        change.setStatus(STATE_LOCAL_MODIFIED);
1205
                                        change.update(changesStore);
1206
                                    }
1207
                                }
1208
                                return ERR_OK;
1209
                            case OP_DELETE:
1210
                                LOGGER.warn("A update change cannot be added as there is a previous change with operation delete (featureCode=" + featureCode + ")");
1211
                                return ERR_CANT_ADD_CHANGE;
1212
                            default:
1213
                                LOGGER.warn("A update change cannot be added as there is a previous change with operation " + previousOperation + " (featureCode=" + featureCode + ")");
1214
                                return ERR_OK;
1215
                        }
1216
                    case OP_DELETE:
1217
                        // Aqui no deberia llegar
1218
                        return ERR_CANT_ADD_CHANGE;
1219
                }
1220
                return ERR_OK;
1221
            }
1222

    
1223
            WorkspaceChangeRow change = new WorkspaceChangeRow(this, changesStore.createNewFeature());
1224
            change.newCode();
1225
            change.setEditingSession(editingSession);
1226
            change.setEntityCode(entity.getEntityCode());
1227
            change.setFeatureCode(featureCode);
1228
            change.setOperation(operation);
1229
            change.setLabel(feature.getString(entity.getFieldForLabel()));
1230
            if (oldFeature != null) {
1231
                change.setData(oldFeature.toJson().toString());
1232
            }
1233
            // Si cambiamos este true, no solo fallaran los test, la importacion
1234
            // del historico habria que tocarla tambien.
1235
            change.setSelected(true);
1236
            switch (operation) {
1237
                case OP_INSERT:
1238
                    change.setStatus(STATE_LOCAL_NEW);
1239
                    break;
1240
                case OP_UPDATE:
1241
                    change.setStatus(STATE_LOCAL_MODIFIED);
1242
                    break;
1243
            }
1244

    
1245
            change.insert(changesStore);
1246
            if (previousOperations != null) {
1247
                previousOperations.put(featureCode, change.getOperation());
1248
            }
1249
            updateEntityState(entity, change.getOperation());
1250

    
1251
            return ERR_OK;
1252
        } catch (Exception ex) {
1253
            LOGGER.warn("Can't add change (op " + OnlineUtils.getOperationLabel(operation) + ", " + entity.getEntityName() + ")", ex);
1254
            return ERR_CANT_ADD_CHANGE;
1255
        }
1256
    }
1257

    
1258
    public int addDeleteChanges(String editingSession, FeatureStore userStore, Expression exp) {
1259
        String entityName = StoreProperties.getEntityName(userStore);
1260
        if (StringUtils.isBlank(entityName)) {
1261
            return ERR_STORE_NOT_IN_WORKINGCOPY;
1262
        }
1263
        if (this.isInStoreIgnoreChanges(userStore)) {
1264
            return ERR_NO_ERROR;
1265
        }
1266
        EntityRow entity = this.getWorkspaceEntityByName(entityName);
1267
        if (entity == null) {
1268
            return ERR_STORE_NOT_IN_WORKINGCOPY;
1269
        }
1270
        if( entity.getState()==STATE_DISCONNECTED ) {
1271
            return ERR_OK;
1272
        }
1273
        FeatureStore workspaceChangesStore = null;
1274
        int err = ERR_CANT_OPEN_CHANGES;
1275
        try {
1276
            workspaceChangesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME,false);
1277
            workspaceChangesStore.edit(FeatureStore.MODE_PASS_THROUGH);
1278
            FeatureSet deletedsFeatures = userStore.getFeatureSet(exp);
1279
            err = ERR_CANT_INSERT_CHANGE;
1280
            for (Feature f : deletedsFeatures) {
1281
                addDeleteChange(editingSession, 
1282
                        entity, 
1283
                        workspaceChangesStore, 
1284
                        f.getLong(entity.getFeatureIdFieldName()), 
1285
                        f.getString(entity.getFieldForLabel()), 
1286
                        f
1287
                );
1288
            }
1289
            workspaceChangesStore.finishEditing();
1290
            err = ERR_NO_ERROR;
1291
        } catch (Exception ex) {
1292
            LOGGER.warn("Can't add  delete changes.", ex);
1293
            FeatureStore.cancelEditingQuietly(workspaceChangesStore);
1294
        } finally {
1295
            DisposeUtils.disposeQuietly(workspaceChangesStore);
1296
        }
1297
        return err;
1298
    }
1299
    
1300
    
1301
    private int addDeleteChange(String editingSession, EntityRow entity, FeatureStore changesStore, long featureCode, String label, Feature oldFeature) {
1302
        if (entity.getState() == STATE_DISCONNECTED) {
1303
            return ERR_OK;
1304
        }
1305
        try {
1306
            WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
1307
            WorkspaceChangeRow previousChange = changesTable.find(this, changesStore, entity.getEntityCode(), featureCode);
1308
            if (previousChange != null) {
1309

    
1310
                /*
1311
                DEL - INS -> Se actualiza el cambio anterior para ignorarlo, se asocia a esta sessi?n y salir con OK
1312
                DEL - UPD -> Se actualiza el cambio anterior a DELETE, se asocia a esta sessi?n y salir con OK
1313
                DEL - DEL -> No hace nada y sale con Error
1314
                 */
1315
                switch (previousChange.getOperation()) {
1316
                    case OP_INSERT:
1317
                        //Al terminar edici?n si todo va bien hay que borrar este registro
1318
                        // si falla, hay que modificarlo para devolverle la operaci?n
1319
                        previousChange.setOperation(OP_IGNORE);
1320
                        previousChange.setSelected(true);
1321
                        // Para recuperarse en caso de que falle la finalizacion de edicion
1322
                        previousChange.setPreviousOperation(OP_INSERT);
1323
                        previousChange.setEditingSession(editingSession);
1324
                        previousChange.update(changesStore);
1325
                        updateEntityState(entity, previousChange.getOperation());
1326
                        return ERR_OK;
1327
                    case OP_UPDATE:
1328
                        //Al terminar edici?n 
1329
                        // si falla, hay que modificarlo para devolverle la operaci?n
1330
                        previousChange.setOperation(OP_DELETE);
1331
                        previousChange.setSelected(true);
1332
                        // Para recuperarse en caso de que falle la finalizacion de edicion
1333
                        previousChange.setPreviousOperation(previousChange.getOperation());
1334
                        previousChange.setEditingSession(editingSession);
1335
                        previousChange.update(changesStore);
1336
                        updateEntityState(entity, previousChange.getOperation());
1337
                        return ERR_OK;
1338
                    case OP_DELETE:
1339
                        LOGGER.warn("A delete change cannot be added as there is a previous change with operation delete (featureCode=" + featureCode + ")");
1340
                        return ERR_CANT_ADD_CHANGE;
1341
                    case OP_IGNORE:
1342
                        LOGGER.warn("A delete change cannot be added as there is a previous change with operation ignore (featureCode=" + featureCode + ")");
1343
                        return ERR_CANT_ADD_CHANGE;
1344
                    default:
1345
                        LOGGER.warn("A delete change cannot be added as there is a previous change with operation " + previousChange.getOperation() + " (featureCode=" + featureCode + ")");
1346
                }
1347
            }
1348

    
1349
            WorkspaceChangeRow change = new WorkspaceChangeRow(this, changesStore.createNewFeature());
1350
            change.newCode();
1351
            change.setPreviousOperation(OP_UNKNOWN);
1352
            change.setEditingSession(editingSession);
1353
            change.setEntityCode(entity.getEntityCode());
1354
            change.setFeatureCode(featureCode);
1355
            change.setOperation(OP_DELETE);
1356
            change.setLabel(label);
1357
            if (oldFeature != null) {
1358
                change.setData(oldFeature.toJson().toString());
1359
            }
1360
            // Si cambiamos este true, no solo fallaran los test, la importacion
1361
            // del historico habria que tocarla tambien.
1362
            change.setSelected(true);
1363
            change.setStatus(STATE_LOCAL_MODIFIED);
1364
            change.insert(changesStore);
1365
            updateEntityState(entity, change.getOperation());
1366
            return ERR_OK;
1367
        } catch (Exception ex) {
1368
            LOGGER.warn("Can't add delete change (" + entity.getEntityName() + ")", ex);
1369
            return ERR_CANT_ADD_CHANGE;
1370
        }
1371
    }
1372

    
1373
    private void updateEntityState(EntityRow entity, int operation) throws DataException {
1374
        if (entity.getState() == STATE_DISCONNECTED) {
1375
            return;
1376
        }
1377
        boolean save = false;
1378
        switch (operation) {
1379
            case OP_INSERT:
1380
            case OP_DELETE:
1381
            case OP_UPDATE:
1382
            case OP_IGNORE:
1383
                switch (entity.getState()) {
1384
                    case STATE_LOCAL_MODIFIED:
1385
                    case STATE_LOCAL_NEW:
1386
                    case STATE_CONFLICT:
1387
                    case STATE_LOCAL_OUTDATED_AND_MODIFIED:
1388
                        break;
1389
                    case STATE_LOCAL_UNMODIFIED:
1390
                        entity.setState(STATE_LOCAL_MODIFIED);
1391
                        save = true;
1392
                        break;
1393
                    case STATE_LOCAL_OUTDATED:
1394
                        entity.setState(STATE_LOCAL_OUTDATED_AND_MODIFIED);
1395
                        save = true;
1396
                        break;
1397
                    case STATE_REMOTE_NEW:
1398
                    case STATE_UNKNOWN:
1399
                    default:
1400
                        //This case is impossible
1401
                        break;
1402
                }
1403
                break;
1404
//            case OP_ADD_ENTITY:
1405
//                entity.setState(STATE_LOCAL_NEW);
1406
//                save = true;
1407
//                break;
1408
        }
1409

    
1410
        if (save) {
1411
            FeatureStore entitiesStore = null;
1412
            try {
1413
                entitiesStore = this.openFeatureStore(EntitiesTable.TABLE_NAME, true);
1414
                entitiesStore.edit(FeatureStore.MODE_FULLEDIT);
1415

    
1416
                entity.update(entitiesStore);
1417
                entitiesStore.finishEditing();
1418
            } finally {
1419
                DisposeUtils.disposeQuietly(entitiesStore);
1420
            }
1421
        }
1422

    
1423
    }
1424

    
1425
    private void updateEntityState(EntityRow entity, boolean save) throws DataException {
1426
        if (entity.getState() == STATE_DISCONNECTED) {
1427
            return;
1428
        }
1429
        if (save) {
1430
            FeatureStore entitiesStore = null;
1431
            try {
1432
                entitiesStore = this.openFeatureStore(EntitiesTable.TABLE_NAME, true);
1433
                entitiesStore.edit(FeatureStore.MODE_FULLEDIT);
1434
                entity.updateState();
1435
                entity.update(entitiesStore);
1436
                entitiesStore.finishEditing();
1437
            } finally {
1438
                DisposeUtils.disposeQuietly(entitiesStore);
1439
            }
1440
        } else {
1441
            entity.updateState();
1442
        }
1443
    }
1444

    
1445
    private Map<Long, Integer> calculatePreviousOperations(EntityRow entity, FeatureStore changesStore, Iterator<Feature> insertedsFeatures, Iterator<Feature> updatedsFeatures) {
1446
        // Esta version agrupa las consultas a la base de datos de 200 en 200
1447
        // para reducir el numero de consultas y aumentar el rendimiento.
1448
        try {
1449
            Map<Long, Integer> previousOperations = new HashMap<>();
1450
            Iterator<Feature> it = new ChainedIterator<>(insertedsFeatures, updatedsFeatures);
1451
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
1452
            int count = 0;
1453
            while (it.hasNext()) {
1454
                Feature feature = it.next();
1455
                String featureCode = feature.getString(entity.getFeatureIdFieldName());
1456
                builder.or(
1457
                        builder.eq(
1458
                                builder.column(WorkspaceChangesTable.FEATUREID),
1459
                                builder.constant(featureCode)
1460
                        )
1461
                );
1462
                count++;
1463
                String filter = builder.build();
1464
                if (!it.hasNext() || count == 200) { //|| StringUtils.length(filter)>(1024*3) ) {
1465
                    if (filter != null) {
1466
                        FeatureSet set = changesStore.getFeatureSet(filter);
1467
                        for (Feature previousChange : set) {
1468
                            if (previousChange != null) {
1469
                                long featureCode2 = previousChange.getLong(WorkspaceChangesTable.FEATUREID);
1470
                                int previousOperation = previousChange.getInt(WorkspaceChangesTable.OPERATION);
1471
                                previousOperations.put(featureCode2, previousOperation);
1472
                            }
1473
                        }
1474
                        DisposeUtils.disposeQuietly(set);
1475
                    }
1476
                    builder = ExpressionUtils.createExpressionBuilder();
1477
                    count = 0;
1478
                }
1479
            }
1480
            ((Rewind) insertedsFeatures).rewind();
1481
            ((Rewind) updatedsFeatures).rewind();
1482
            return previousOperations;
1483
        } catch (Exception ex) {
1484
            LOGGER.warn("Can't calculate previus operations.", ex);
1485
            return null;
1486
        }
1487
    }
1488

    
1489
    public int cancelChanges(FeatureStore store, String editingSession) {
1490
        String entityName = StoreProperties.getEntityName(store);
1491
        if (StringUtils.isBlank(entityName)) {
1492
            return ERR_STORE_NOT_IN_WORKINGCOPY;
1493
        }
1494
        if (this.isInStoreIgnoreChanges(store)) {
1495
            LOGGER.debug("===: CANCEL_CHANGES: Skip (" + store.getName() + ")");
1496
            return ERR_NO_ERROR;
1497
        }
1498
        EntityRow entity = this.getWorkspaceEntityByName(entityName);
1499
        if (entity == null) {
1500
            return ERR_STORE_NOT_IN_WORKINGCOPY;
1501
        }
1502
        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
1503
        changesTable.revertChangedLocalChanges(this, entity, editingSession);
1504
        changesTable.removeLocalChanges(this, entity, editingSession);
1505
        return ERR_NO_ERROR;
1506
    }
1507

    
1508
    public int acceptChanges(FeatureStore store, String editingSession) {
1509
        String entityName = StoreProperties.getEntityName(store);
1510
        if (StringUtils.isBlank(entityName)) {
1511
            return ERR_STORE_NOT_IN_WORKINGCOPY;
1512
        }
1513
        if (this.isInStoreIgnoreChanges(store)) {
1514
            LOGGER.debug("===: CANCEL_CHANGES: Skip (" + store.getName() + ")");
1515
            return ERR_NO_ERROR;
1516
        }
1517
        EntityRow entity = this.getWorkspaceEntityByName(entityName);
1518
        if (entity == null) {
1519
            return ERR_STORE_NOT_IN_WORKINGCOPY;
1520
        }
1521
        if (entity.getState() == STATE_DISCONNECTED) {
1522
            return ERR_OK;
1523
        }
1524
        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
1525
        changesTable.removeIgnoredLocalChanges(this, entity, editingSession);
1526
        return ERR_NO_ERROR;
1527
    }
1528

    
1529
    @Override
1530
    public OnlineChanges<OnlineWorkingcopyChange> getLocalChanges() {
1531
        return getLocalChanges(null);
1532
    }
1533

    
1534
    @Override
1535
    public OnlineChanges<OnlineWorkingcopyChange> getLocalChanges(List<OnlineEntity> entities) {
1536
        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
1537
        ChangesImpl changes = new ChangesImpl<WorkspaceChangeRow>(changesTable.getByEntityCode(this, entities), WorkspaceChangesTable.SELECTED) {
1538
            @Override
1539
            protected WorkspaceChangeRow createChange(Feature f) {
1540
                return new WorkspaceChangeRow(OnlineWorkspaceImpl.this, f);
1541
            }
1542

    
1543
            @Override
1544
            protected void updateChange(FeatureStore store, WorkspaceChangeRow change) {
1545
                change.update(store);
1546
            }
1547

    
1548
        };
1549
        return changes;
1550
    }
1551

    
1552
    public boolean hasLocalChanges(List<OnlineEntity> entities) {
1553
        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
1554
        boolean hasChanges = changesTable.hasLocalChangesByEntityCode(this, entities);
1555
        return hasChanges;
1556
    }
1557

    
1558
    @Override
1559
    public List<OnlineEntity> getWorkspaceEntities() {
1560
        if (disposed) {
1561
            return Collections.EMPTY_LIST;
1562
        }
1563
        List<OnlineEntity> entities = new ArrayList<>();
1564
        entities.addAll(this.getEntitiesAsEntityRow());
1565
        return entities;
1566
    }
1567

    
1568
    private Collection<EntityRow> getEntitiesAsEntityRow() {
1569
        if (this.workspaceEntitiesByName == null) {
1570
            reloadWorkspaceEntities();
1571
        }
1572
        return this.workspaceEntitiesByName.values();
1573
    }
1574

    
1575
    @Override
1576
    public EntityRow getWorkspaceEntityByName(String name) {
1577
        if (this.workspaceEntitiesByName == null) {
1578
            this.reloadWorkspaceEntities();
1579
        }
1580
        return this.workspaceEntitiesByName.get(name);
1581
    }
1582

    
1583
    @Override
1584
    public EntityRow getWorkspaceEntityByCode(String code) {
1585
        if (this.workspaceEntitiesByCode == null) {
1586
            this.reloadWorkspaceEntities();
1587
        }
1588
        return this.workspaceEntitiesByCode.get(code);
1589
    }
1590

    
1591
    private void addWorkspaceEntity(EntityRow entity) {
1592
        if (this.workspaceEntitiesByCode == null) {
1593
            this.reloadWorkspaceEntities();
1594
        }
1595
        this.workspaceEntitiesByCode.put(entity.getEntityCode(), entity);
1596
        this.workspaceEntitiesByName.put(entity.getEntityName(), entity);
1597
    }
1598

    
1599
    private boolean existsInWorkspace(String entity) {
1600
        // No hacer publico este metodo ya que es peligroso que se consulte si existe
1601
        // una entidad por nombre. Nos ha pasado ya que el nombre de entidad existe
1602
        // pero con un codigo distinto.
1603
        EntityRow lentity = this.getWorkspaceEntity(entity);
1604
        return lentity != null;
1605
    }
1606

    
1607
    @Override
1608
    public boolean existsInWorkspace(OpenFeatureStoreParameters parameters) {
1609
        if (!this.isInMyDatabase(parameters)) {
1610
            return false;
1611
        }
1612
        JDBCStoreParameters params = (JDBCStoreParameters) parameters;
1613
        return this.existsInWorkspace(params.getTable());
1614
    }
1615

    
1616
    @Override
1617
    public boolean existsInWorkspace(OnlineEntity entity) {
1618
        if (entity == null) {
1619
            return false;
1620
        }
1621
        if (this.existsInWorkspace(entity.getEntityName())) {
1622
            return true;
1623
        }
1624
        return this.existsInWorkspace(entity.getEntityCode());
1625
    }
1626

    
1627
    @Override
1628
    public EntityRow getWorkspaceEntity(String entity) {
1629
        EntityRow wsentity = this.getWorkspaceEntityByCode(entity);
1630
        if (wsentity == null) {
1631
            wsentity = this.getWorkspaceEntityByName(entity);
1632
        }
1633
        return wsentity;
1634
    }
1635

    
1636
    @Override
1637
    public OnlineSite getSite() {
1638
        return this.project.getSite();
1639
    }
1640

    
1641
    public OnlineProject getProject() {
1642
        return this.project;
1643
    }
1644

    
1645
    @Override
1646
    public List<OnlineEntity> getEntitiesOfRemoteChanges() {
1647
        List<OnlineEntity> res = new ArrayList<>();
1648
        RemoteChangesTable changesTable = new RemoteChangesTable();
1649
        DisposableFeatureSetIterable features = changesTable.getGroupedByEntity(this);
1650
        EntitiesTable entitiesTable = new EntitiesTable();
1651
        for (Feature feature : features) {
1652
            OnlineEntity entity = entitiesTable.getByEntityCode(this, feature.getString(RemoteChangesTable.COD_ENTITY));
1653
            res.add(entity);
1654
        }
1655
        DisposeUtils.disposeQuietly(features);
1656
        return res;
1657
    }
1658

    
1659
    @Override
1660
    public List<OnlineEntity> getEntitiesOfLocalChanges() {
1661
        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
1662
        List<OnlineEntity> entities = new ArrayList<>();
1663

    
1664
        DisposableFeatureSetIterable changesGroupedByEntity = changesTable.getGroupedByEntity(this);
1665

    
1666
        for (Feature fchange : changesGroupedByEntity) {
1667
            WorkspaceChangeRow change = new WorkspaceChangeRow(this, fchange);
1668
            OnlineEntity localEntity = change.getEntity();
1669
            if (change.isSelected()) {
1670
                entities.add(localEntity);
1671
            }
1672
        }
1673
        return entities;
1674
    }
1675

    
1676
    @Override
1677
    public void addToConnectionPool() {
1678
        JDBCServerExplorerParameters params = this.getExplorerParameters();
1679
        DataManager dataManager = DALLocator.getDataManager();
1680
        dataManager.getDataServerExplorerPool().add(this.getLabel(), params);
1681
    }
1682

    
1683
    @Override
1684
    public boolean isInMyDatabase(FeatureStore store) {
1685
        if (!(store.getParameters() instanceof JDBCStoreParameters)) {
1686
            return false;
1687
        }
1688
        JDBCStoreParameters storeParams = (JDBCStoreParameters) store.getParameters();
1689
        JDBCServerExplorerParameters explorerParams = this.getExplorerParameters();
1690
        if (!StringUtils.equalsIgnoreCase(storeParams.getProviderName(), explorerParams.getProviderName())) {
1691
            return false;
1692
        }
1693
        return StringUtils.equalsIgnoreCase(storeParams.getUrl(), explorerParams.getUrl());
1694
    }
1695

    
1696
    @Override
1697
    public boolean isInMyDatabase(OpenFeatureStoreParameters parameters) {
1698
        if (!(parameters instanceof JDBCStoreParameters)) {
1699
            return false;
1700
        }
1701
        JDBCStoreParameters storeParams = (JDBCStoreParameters) parameters;
1702
        JDBCServerExplorerParameters explorerParams = this.getExplorerParameters();
1703
        if (!StringUtils.equalsIgnoreCase(storeParams.getProviderName(), explorerParams.getProviderName())) {
1704
            return false;
1705
        }
1706
        return StringUtils.equalsIgnoreCase(storeParams.getUrl(), explorerParams.getUrl());
1707
    }
1708

    
1709
    @Override
1710
    public boolean isInMyDatabase(String tableName) {
1711
        try {
1712
            if (StringUtils.isBlank(tableName)) {
1713
                return false;
1714
            }
1715
            JDBCServerExplorer explorer = this.getExplorer();
1716
            JDBCServerExplorerParameters explorerParams = explorer.getParameters();
1717
            if (explorerParams instanceof HasAFile) {
1718
                File f = ((HasAFile) explorerParams).getFile();
1719
                if (!f.exists()) {
1720
                    return false;
1721
                }
1722
            }
1723
            JDBCStoreParameters parameters = explorer.get(tableName);
1724
            if (!explorer.exists(parameters)) {
1725
                return false;
1726
            }
1727
            return true;
1728
        } catch (DataException ex) {
1729
            return false;
1730
        }
1731
    }
1732

    
1733
    @Override
1734
    public Feature getRelatedFeature(OnlineEntity entity, long featureCode) {
1735
        FeatureStore store = null;
1736
        try {
1737
            store = this.getFeatureStore(entity.getEntityName());
1738
            Feature f = store.findFirst("\"" + entity.getFeatureIdFieldName() + "\"=" + featureCode);
1739
            return f;
1740
        } catch (Exception ex) {
1741
            throw new RuntimeException("Can't retrieve feature '" + entity.getEntityName() + "/" + code + "'.", ex);
1742
        } finally {
1743
            DisposeUtils.disposeQuietly(store);
1744
        }
1745

    
1746
    }
1747

    
1748
    @Override
1749
    public Feature getRelatedFeature(OnlineRemoteChange change) {
1750
        EntityRow entity = this.getWorkspaceEntity(change.getEntityCode());
1751
        return getRelatedFeature(entity, change.getRelatedFeatureCode());
1752
    }
1753

    
1754
    @Override
1755
    public int removeEntity(OnlineEntity entity) {
1756
        if (entity == null) {
1757
            return ERR_INVALID_ENTITY;
1758
        }
1759
        int err = ERR_NO_ERROR;
1760
        DataTransaction transaction = DALLocator.getDataManager().createTransaction();
1761
        try {
1762
            transaction.begin();
1763
            EntityRow entity1 = this.getWorkspaceEntityByCode(entity.getEntityCode());
1764
            EntityRow entity2 = this.getWorkspaceEntityByName(entity.getEntityName());
1765
            if (entity1 != null && entity2 != null
1766
                    && StringUtils.equalsIgnoreCase(entity1.getEntityName(), entity2.getEntityName())
1767
                    && StringUtils.equalsIgnoreCase(entity1.getEntityCode(), entity2.getEntityCode())) {
1768
                err = doRemoveEntity(entity1, transaction);
1769
            } else if (entity1 != null) {
1770
                err = doRemoveEntity(entity1, transaction);
1771
            } else if (entity2 != null) {
1772
                err = doRemoveEntity(entity2, transaction);
1773
            } else {
1774
                err = doRemoveEntity(entity, transaction);
1775
            }
1776
            transaction.commit();
1777
            forceReloadWorkspaceEntities();
1778
            return ERR_OK;
1779
        } catch (Exception ex) {
1780
            LOGGER.warn("Can't remove entity.", ex);
1781
            transaction.rollbackQuietly();
1782
            return err;
1783
        } finally {
1784
            DisposeUtils.disposeQuietly(transaction);
1785
        }
1786
    }
1787

    
1788
    @Override
1789
    public int removeEntities(List<String> namesOrCodes) {
1790
        int err = ERR_NO_ERROR;
1791
        DataTransaction transaction = DALLocator.getDataManager().createTransaction();
1792

    
1793
        try {
1794
            transaction.begin();
1795
            for (String nameOrCode : namesOrCodes) {
1796
                EntityRow entity = (EntityRow) this.getWorkspaceEntity(nameOrCode);
1797
                if (entity == null) {
1798
                    err = ERR_ENTITY_NOT_EXISTS;
1799
                    return err;
1800
                }
1801

    
1802
                doRemoveEntity(entity, transaction);
1803
            }
1804

    
1805
            transaction.commit();
1806
            forceReloadWorkspaceEntities();
1807
            return ERR_OK;
1808
        } catch (Exception ex) {
1809
            LOGGER.warn("Can't remove entity.", ex);
1810
            transaction.rollbackQuietly();
1811
            return err;
1812
        } finally {
1813
            DisposeUtils.disposeQuietly(transaction);
1814
        }
1815

    
1816
    }
1817

    
1818
    private int doRemoveEntity(OnlineEntity entity, DataTransaction transaction) throws DataException {
1819
        int err;
1820
        LOGGER.debug("===: REMOVE ENTITY " + entity.getEntityName());
1821
        //Eliminamos todos los cambios de esta entidad
1822
        err = ERR_CANT_REMOVE_CHANGES;
1823
        FeatureStore changesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME, true);
1824
        transaction.add(changesStore);
1825
        changesStore.edit(MODE_FULLEDIT);
1826
        changesStore.delete("\"" + WorkspaceChangesTable.COD_ENTITY + "\"='" + entity.getEntityCode() + "'");
1827
        changesStore.finishEditing();
1828
        FeatureStore remoteChangesStore = this.openFeatureStore(RemoteChangesTable.TABLE_NAME, true);
1829
        transaction.add(remoteChangesStore);
1830
        remoteChangesStore.edit(MODE_FULLEDIT);
1831
        remoteChangesStore.delete("\"" + RemoteChangesTable.COD_ENTITY + "\"='" + entity.getEntityCode() + "'");
1832
        remoteChangesStore.finishEditing();
1833
        err = ERR_CANT_REMOVE_ENTITY;
1834
        //Eliminamos la entidad
1835
        FeatureStore entitiesStore = openFeatureStore(EntitiesTable.TABLE_NAME, true);
1836
        transaction.add(entitiesStore);
1837
        entitiesStore.edit(MODE_FULLEDIT);
1838
        entitiesStore.delete("\"" + EntitiesTable.COD_ENTITY + "\"='" + entity.getEntityCode() + "'");
1839
        entitiesStore.finishEditing();
1840
        err = ERR_CANT_REMOVE_ENTITY;
1841
        //Eliminamos el DALFILE
1842
        FeatureStore store = this.openFeatureStore(entity);
1843
        if (store != null) {
1844
            transaction.add(store);
1845
            ResourcesStorage resourcesStorage = store.getResourcesStorage();
1846
            if (resourcesStorage != null) {
1847
                ResourcesStorage.Resource resource = resourcesStorage.getResource("dal");
1848
                if (resource != null) {
1849
                    resourcesStorage.remove(resource.getName());
1850
                }
1851
            }
1852

    
1853
            //Eliminamos el store
1854
            transaction.add(this.wsexplorer, false);
1855
            this.wsexplorer.remove(store.getParameters());
1856
        }
1857
        return err;
1858
    }
1859

    
1860
    public boolean isInStoreIgnoreChanges(FeatureStore store) {
1861
        if (this.storeIgnoreChanges == null) {
1862
            return false;
1863
        }
1864
        return this.storeIgnoreChanges.contains(store);
1865
    }
1866

    
1867
    private void addStoreIgnoreChanges(FeatureStore store) {
1868
        if (this.storeIgnoreChanges == null) {
1869
            this.storeIgnoreChanges = new HashSet<>();
1870
        }
1871
        this.storeIgnoreChanges.add(store);
1872
    }
1873

    
1874
    private void removeStoreIgnoreChanges(FeatureStore store) {
1875
        if (store == null) {
1876
            return;
1877
        }
1878
        if (this.storeIgnoreChanges == null) {
1879
            this.storeIgnoreChanges = new HashSet<>();
1880
        }
1881
        this.storeIgnoreChanges.remove(store);
1882
    }
1883

    
1884
    public boolean isCorrupt(OnlineEntity entity, FeatureStore store, int level) {
1885
        return isCorrupt(entity, store, level, true);
1886

    
1887
    }
1888

    
1889
    public boolean isCorrupt(OnlineEntity lentity, FeatureStore store, int level, boolean saveToDisk) {
1890
        int stateMask = lentity.getState();
1891
        if ((stateMask & STATE_CORRUPT) == STATE_CORRUPT) {
1892
            return true;
1893
        }
1894
        if ((stateMask & STATE_DISCONNECTED) == STATE_DISCONNECTED) {
1895
            return false;
1896
        }
1897
        boolean corrupt = false;
1898

    
1899
        FeatureType storeft = store.getDefaultFeatureTypeQuietly();
1900
        if (storeft.get(lentity.getFeatureIdFieldName()) == null) {
1901
            corrupt = true;
1902
        }
1903
        // ... mas chequeos aqui si se nos ocurren...
1904

    
1905
        if (corrupt) {
1906
            LOGGER.warn("The table or entity '" + lentity.getEntityName() + "' is corrupt. Missing requiered field '" + lentity.getFeatureIdFieldName() + "'.");
1907
            if (lentity instanceof EntityRow) {
1908
                EntityRow rowEntity = (EntityRow) lentity;
1909
                try {
1910
                    if ((stateMask & (STATE_DISCONNECTED | STATE_CORRUPT)) != (STATE_DISCONNECTED | STATE_CORRUPT)) {
1911
                        rowEntity.setState(STATE_DISCONNECTED | STATE_CORRUPT);
1912
                        if (saveToDisk) {
1913
                            rowEntity.update();
1914
                        }
1915
                    }
1916
                } catch (Throwable t) {
1917
                    if (LOGGER.isDebugEnabled()) {
1918
                        LOGGER.debug("Can't mark as disconected the entity '" + lentity.getEntityName() + "'.", t);
1919
                    } else {
1920
                        LOGGER.warn("Can't mark as disconected the entity '" + lentity.getEntityName() + "'.");
1921
                    }
1922
                }
1923
            }
1924
        }
1925
        return corrupt;
1926
    }
1927

    
1928
    public void initialize() {
1929
        VarsTable varsTable = new VarsTable();
1930
        varsTable.set(this, CONFIG_WORKSPACE_CODE_NAME, code);
1931
        varsTable.set(this, CONFIG_WORKSPACE_LABEL_NAME, label);
1932
        varsTable.set(this, CONFIG_PROJECT_NAME, project.toJson().toString());
1933
        varsTable.set(this, CONFIG_OFFLINE, BooleanUtils.toStringTrueFalse(this.offline));
1934
        varsTable.set(this, CONFIG_ENTITY_LABEL_TEMPLATE, this.entityLabelTemplate);
1935
    }
1936

    
1937
    @Override
1938
    public List<OnlineEntity> getEntitiesWithSelectedChanges() {
1939

    
1940
        List<OnlineEntity> entities = new ArrayList<>();
1941
        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
1942
        DisposableFeatureSetIterable changesGroupedByEntity = null;
1943
        try {
1944

    
1945
            changesGroupedByEntity = changesTable.getGroupedByEntity(this);
1946
            for (Feature fchange : changesGroupedByEntity) {
1947
                WorkspaceChangeRow change = new WorkspaceChangeRow(this, fchange);
1948
                OnlineEntity entity = change.getEntity();
1949
                if (change.isSelected()) {
1950
                    entities.add(entity);
1951
                }
1952
            }
1953
            return entities;
1954

    
1955
        } catch (Exception ex) {
1956
            return null;
1957
        } finally {
1958
            DisposeUtils.dispose(changesGroupedByEntity);
1959
        }
1960
    }
1961

    
1962
    @Override
1963
    public List<String> getDataModels() {
1964
        List<OnlineEntity> entities = getWorkspaceEntities();
1965
        Set<String> dataModels = new HashSet();
1966
        for (OnlineEntity entity : entities) {
1967
            List<String> dataModelsEntity = entity.getDataModelsAsList();
1968
            dataModels.addAll(dataModelsEntity);
1969
        }
1970
        ArrayList<String> list = new ArrayList<>(dataModels);
1971
        Collections.sort(list);
1972
        return list;
1973
    }
1974

    
1975
    @Override
1976
    public void logout() {
1977
        this.getSite().logout();
1978
    }
1979

    
1980
    @Override
1981
    public void registerDataModelRepository(String modelName) {
1982
//        DataManager dataManager = DALLocator.getDataManager();
1983
//        String modelResources = null;
1984
//        BaseStoresRepository modelRepository = null;
1985
//        for (OnlineEntity entity : this.getWorkspaceEntities()) {
1986
//            List<String> entityModels = entity.getDataModelsAsList();
1987
//            if( entityModels.contains(modelName) ) {
1988
//                if( modelRepository == null ) {
1989
//                    modelRepository = new BaseStoresRepository(modelName, this.getLabel(), this.getExplorerParameters());
1990
//                    modelRepository.setProperty(STORESREPOSITORY_ONLINE_MODEL, true);
1991
//                    modelRepository.setProperty(STORESREPOSITORY_ONLINE_LOCALURL, this.getExplorerParameters().getUrl());
1992
//                }
1993
//                OpenDataStoreParameters params = this.createOpenStoreParameters(entity.getEntityName());
1994
//                if( modelResources==null && StringUtils.isNotBlank(entity.getResources()) ) {
1995
//                    modelResources = entity.getResources();
1996
//                }
1997
//                modelRepository.add(entity.getEntityName(), params, entity.getLabelOrName());
1998
//            }
1999
//        }
2000
//        if( modelRepository == null ) {
2001
//            return;
2002
//        }
2003
//        StoresRepository globalRepository = dataManager.getStoresRepository();
2004
//        globalRepository.addRepository(modelRepository);
2005
//
2006
//        if (StringUtils.isNotBlank(modelResources)) {
2007
//            try {
2008
//                JDBCServerExplorer explorer = this.getExplorer();
2009
//                explorer.setCustomResources(modelName, modelResources, true);
2010
//            } catch (Throwable t) {
2011
//                LOGGER.warn("Can't register resources for model '" + modelName + "' (resources=" + modelResources + ").", t);
2012
//            }
2013
//        }
2014
//        callModel(modelName, "onConnect", null);
2015
    }
2016

    
2017
//    private Object callModel(String modelName, String functionName, Object[] args) {
2018
//        ResourcesStorage modelResourcesStorge = null;
2019
//        try {
2020
//            JDBCServerExplorer explorer = this.getExplorer();
2021
//            modelResourcesStorge = explorer.getResourcesStorage(modelName);
2022
//            Script script = ExpressionUtils.getScript(modelResourcesStorge,"modelsc");
2023
//            if( script!=null ) {
2024
//                return script.invokeFunction(functionName, args);
2025
//            }
2026
//        } catch(Throwable t) {
2027
//            LOGGER.warn("Can't call '"+functionName+"' for model '"+modelName+"'.", t);
2028
//        } finally {
2029
//            DisposeUtils.disposeQuietly(modelResourcesStorge);
2030
//        }
2031
//        return null;
2032
//    }
2033
    @Override
2034
    public boolean isOffline() {
2035
        return this.offline;
2036
    }
2037

    
2038
    @Override
2039
    public void setOffline(boolean offline) {
2040
        this.offline = offline;
2041
    }
2042

    
2043
    @Override
2044
    public String getEntityLabelTemplate() {
2045
        return this.entityLabelTemplate;
2046
    }
2047

    
2048
    @Override
2049
    public String formatEntityLabel(OnlineEntity entity) {
2050
        String s = OnlineUtils.getFormatedLabel(entity, this.entityLabelTemplate);
2051
        if (s == null) {
2052
            s = entity.getLabelOrName();
2053
        }
2054
        return s;
2055
    }
2056

    
2057
    @Override
2058
    public void setConfigValue(String name, String value) {
2059
        VarsTable varsTable = new VarsTable();
2060
        varsTable.set(this, name, value);
2061
    }
2062

    
2063
    @Override
2064
    public OnlineChanges<OnlineRemoteChange> getRemoteChanges() {
2065
        return getRemoteChangesByEntity((String) null);
2066
    }
2067

    
2068
    @Override
2069
    public OnlineChanges<OnlineRemoteChange> getRemoteChangesByEntity(String... entityNames) {
2070
        String[] entityCodes = null;
2071
        if (ArrayUtils.isNotEmpty(entityNames)) {
2072
            entityCodes = new String[entityNames.length];
2073
            for (int i = 0; i < entityNames.length; i++) {
2074
                String entityName = entityNames[i];
2075
                if (StringUtils.isBlank(entityName)) {
2076
                    entityCodes[i] = null;
2077
                } else {
2078
                    OnlineEntity entity = this.getWorkspaceEntity(entityName);
2079
                    if (entity == null) {
2080
                        return null;
2081
                    }
2082
                    entityCodes[i] = entity.getEntityCode();
2083
                }
2084
            }
2085
        }
2086
        RemoteChangesTable changesTable = new RemoteChangesTable();
2087
        GetItemWithSize64<Feature> changesByEntity = changesTable.getByEntityCode(this, entityCodes);
2088
        ChangesImpl changes = new ChangesImpl<RemoteChangeRow>(changesByEntity, RemoteChangesTable.SELECTED) {
2089
            @Override
2090
            protected RemoteChangeRow createChange(Feature f) {
2091
                return new RemoteChangeRow(OnlineWorkspaceImpl.this, f);
2092
            }
2093

    
2094
            @Override
2095
            protected void updateChange(FeatureStore store, RemoteChangeRow change) {
2096
                change.update(store);
2097
            }
2098

    
2099
        };
2100
        DisposeUtils.disposeQuietly(changesByEntity);
2101
        return changes;
2102
    }
2103

    
2104
    private Timestamp now() {
2105
        return Timestamp.from(LocalDateTime.now().toInstant(ZoneOffset.UTC));
2106
    }
2107

    
2108
    @Override
2109
    public OnlineEntity getEntity(String entityName) {
2110
        OnlineEntity entity = this.getWorkspaceEntity(entityName);
2111
        return entity;
2112
    }
2113

    
2114
    @Override
2115
    public OpenDataStoreParameters createOpenStoreParameters(String tableName) {
2116
        try {
2117
            JDBCStoreParameters params = this.wsexplorer.get(tableName);
2118
            return params;
2119
        } catch (Exception ex) {
2120
            LOGGER.trace("can't create open store parameters from '" + this.getMessageLabel() + "'.", ex);
2121
            return null;
2122
        }
2123
    }
2124

    
2125
    @Override
2126
    protected void doDispose() {
2127
        this.disposed = true;
2128
        for (Map.Entry<String, FeatureStore> entry : storesCache.entrySet()) {
2129
            FeatureStore store = entry.getValue();
2130
            if (store != null) {
2131
                DisposeUtils.disposeQuietly(store);
2132
            }
2133
        }
2134
        this.storesCache.clear();
2135
        DisposeUtils.dispose(this.wsexplorer);
2136
        this.wsexplorer = null;
2137
        this.code = null;
2138
        DisposeUtils.disposeQuietly(project);
2139
    }
2140

    
2141
    @Override
2142
    public int revert(String nameOrCode) {
2143
        return revert(nameOrCode, null);
2144
    }
2145

    
2146
    @Override
2147
    public int revert(String nameOrCode, SimpleTaskStatus status) {
2148
        if (status == null) {
2149
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus("Commit");
2150
            status.setAutoremove(true);
2151
            status.add();
2152
        } else {
2153
            status.push();
2154
        }
2155

    
2156
        FeatureStore entitiesStore = null;
2157
        FeatureStore userStore = null;
2158

    
2159
        DataTransaction transaction = null;
2160
        try {
2161
            LOGGER.debug("===: REVERT " + this.getCode() + ", " + this.getLabel() + ", " + nameOrCode);
2162
            transaction = DALLocator.getDataManager().createTransaction();
2163
            transaction.begin();
2164

    
2165
            status.message("Reverting");
2166

    
2167
            EntityRow entity = this.getWorkspaceEntity(nameOrCode);
2168
            WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
2169
            FeatureStore changesStore = null;
2170
//            String dataCodeFieldName = entity.getFeatureIdFieldName();
2171

    
2172
            DisposableFeatureSetIterable changes = changesTable.getSelectedsByEntityCodeAsIterator(this, entity.getEntityCode());
2173
            transaction.add(changes);
2174

    
2175
            if (!changes.isEmpty()) {
2176
                userStore = this.openFeatureStore(entity);
2177
                this.addStoreIgnoreChanges(userStore);
2178
                transaction.add(userStore, userStore.getName(), true);
2179
                userStore.edit(MODE_PASS_THROUGH);
2180
                changesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME, true);
2181
                transaction.add(changesStore, WorkspaceChangesTable.TABLE_NAME, true);
2182
                changesStore.edit(MODE_PASS_THROUGH);
2183

    
2184
                status.setCurValue(0);
2185
                status.setRangeOfValues(0, changes.size64());
2186
                for (Feature feature : changes) {
2187
                    WorkspaceChangeRow change = new WorkspaceChangeRow(this, feature);
2188
                    change.revert(userStore, changesStore);
2189
                    status.incrementCurrentValue();
2190
                }
2191
                userStore.finishEditing();
2192
                changesStore.finishEditing();
2193
            }
2194

    
2195
            entitiesStore = this.openFeatureStore(EntitiesTable.TABLE_NAME, true);
2196
            transaction.add(entitiesStore, EntitiesTable.TABLE_NAME);
2197
            entitiesStore.edit(FeatureStore.MODE_FULLEDIT);
2198
            entity.updateState(transaction);
2199
            entity.update(entitiesStore);
2200
            entitiesStore.finishEditing();
2201

    
2202
            transaction.commit();
2203
            forceReloadWorkspaceEntities();
2204

    
2205
            status.message("Revert completed");
2206
            status.terminate();
2207
            return ERR_NO_ERROR;
2208
        } catch (Exception ex) {
2209
            LOGGER.warn("Can't revert changes.", ex);
2210
            status.message("Can't revert changes");
2211
            status.abort();
2212
            return ERR_CANT_REVERT;
2213
        } finally {
2214
            this.removeStoreIgnoreChanges(userStore);
2215
            DisposeUtils.disposeQuietly(transaction);
2216
            status.pop();
2217
        }
2218
    }
2219

    
2220
    @Override
2221
    public void download_config(boolean overwrite, SimpleTaskStatus status) {
2222
        OnlineLayer config = this.project.getConfigTable(status);
2223
        if( config == null ) {
2224
            return;
2225
        }
2226
        I18nManager i18n = ToolsLocator.getI18nManager();
2227
        if (status == null) {
2228
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(i18n.getTranslation("_Download_configuration_data"));
2229
            status.setAutoremove(true);
2230
            status.add();
2231
        } else {
2232
            status.push();
2233
        }
2234
        FileInputStream fis = null;
2235
        FeatureStore store = null;
2236
        try {
2237
            status.message(i18n.getTranslation("_Download_configuration_data"));
2238
            status.setIndeterminate();
2239
            OnlineSiteImpl site = this.project.getSite();
2240
            OnlineDownloader downloader = site.getDownloader();            
2241
            File f = downloader.get(site.getURL("/api/v1/layers/" + config.getId() + "/featurelist?max=1000"));
2242
            fis = new FileInputStream(f);
2243
            JsonObject json = Json.createObject(fis);
2244
            if (json.containsKey("content")) {
2245
                json = json.getJsonObject("content");
2246
            }
2247
            int totalfeatures = json.getInt("totalfeatures", -1);
2248
            int lendata = json.getInt("lendata", -1);
2249
            JsonArray features = json.getJsonArray("features");
2250
            DataManager dataManager = DALLocator.getDataManager();
2251
            DatabaseWorkspaceManager dbworkspace = dataManager.getDatabaseWorkspace(this.wsexplorer.getParameters());
2252
            store = dbworkspace.getTable(DatabaseWorkspaceManager.TABLE_CONFIGURATION);
2253
            store.edit(FeatureStore.MODE_FULLEDIT);
2254
            status.setRangeOfValues(0, features.size());
2255
            status.setCurValue(0);
2256
            for (JsonValue feature0_json : features) {
2257
                status.incrementCurrentValue();
2258
                JsonObject feature_json = (JsonObject) feature0_json;
2259
                ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
2260
                String filter = builder.eq(
2261
                        builder.column(FIELD_CONFIGURATION_NAME),
2262
                        builder.constant(feature_json.getString(FIELD_CONFIGURATION_NAME, ""))
2263
                ).toString();
2264
                Feature feature = store.findFirst(filter);
2265
                EditableFeature efeature;
2266
                if (feature == null) {
2267
                    efeature = store.createNewFeature(feature_json);
2268
                    store.insert(efeature);
2269
                } else if( overwrite ) {
2270
                    efeature = feature.getEditable();
2271
                    efeature.set(FIELD_CONFIGURATION_VALUE, feature_json.getString(FIELD_CONFIGURATION_VALUE, ""));
2272
                    store.update(efeature);
2273
                }
2274
            }
2275
            status.setIndeterminate();
2276
            status.message(i18n.getTranslation("_Writing_data"));
2277
            store.finishEditing();
2278
            status.terminate();
2279
        } catch (Exception ex) {
2280
            LOGGER.warn("", ex);
2281
            status.abort();
2282
            throw new RuntimeException("", ex);
2283
        } finally {
2284
            IOUtils.closeQuietly(fis);
2285
            FeatureStore.cancelEditingQuietly(store);
2286
            DisposeUtils.disposeQuietly(store);
2287
            status.pop();
2288
        }
2289
    }
2290

    
2291
    @Override
2292
    public void download_resources(boolean overwrite, SimpleTaskStatus status) {
2293
        OnlineLayer resources = this.project.getResourcesTable(status);
2294
        if( resources == null ) {
2295
            return;
2296
        }
2297
        I18nManager i18n = ToolsLocator.getI18nManager();
2298
        if (status == null) {
2299
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(i18n.getTranslation("_Download_project_resources"));
2300
            status.setAutoremove(true);
2301
            status.add();
2302
        } else {
2303
            status.push();
2304
        }
2305
        FileInputStream fis = null;
2306
        FeatureStore store = null;
2307
        try {
2308
            status.message(i18n.getTranslation("_Download_project_resources"));
2309
            status.setIndeterminate();
2310
            OnlineSiteImpl site = this.project.getSite();
2311
            OnlineDownloader downloader = site.getDownloader();
2312
            File f = downloader.get(site.getURL("/api/v1/layers/" + resources.getId() + "/featurelist?max=1000"));
2313
            fis = new FileInputStream(f);
2314
            JsonObject json = Json.createObject(fis);
2315
            if (json.containsKey("content")) {
2316
                json = json.getJsonObject("content");
2317
            }
2318
            int totalfeatures = json.getInt("totalfeatures", -1);
2319
            int lendata = json.getInt("lendata", -1);
2320
            JsonArray features = json.getJsonArray("features");
2321
            DataManager dataManager = DALLocator.getDataManager();
2322
            DatabaseWorkspaceManager dbworkspace = dataManager.getDatabaseWorkspace(this.wsexplorer.getParameters());
2323
            store = dbworkspace.getTable(DatabaseWorkspaceManager.TABLE_RESOURCES);
2324
            store.edit(FeatureStore.MODE_FULLEDIT);
2325
            status.setRangeOfValues(0, features.size());
2326
            status.setCurValue(0);
2327
            for (JsonValue feature0_json : features) {
2328
                status.incrementCurrentValue();
2329
                JsonObject feature_json = (JsonObject) feature0_json;
2330
                ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
2331
                String filter = builder.eq(
2332
                        builder.column(FIELD_RESOURCES_NAME),
2333
                        builder.constant(feature_json.getString(FIELD_RESOURCES_NAME, ""))
2334
                ).toString();
2335
                Feature feature = store.findFirst(filter);
2336
                EditableFeature efeature;
2337
                if (feature == null) {
2338
                    efeature = store.createNewFeature(feature_json);
2339
                    store.insert(efeature);
2340
                } else if( overwrite ) {
2341
                    efeature = feature.getEditable();
2342
                    efeature.set(FIELD_RESOURCES_RESOURCE, feature_json.getString(FIELD_RESOURCES_RESOURCE, ""));
2343
                    store.update(efeature);
2344
                }
2345
            }
2346
            status.setIndeterminate();
2347
            status.message(i18n.getTranslation("_Writing_data"));
2348
            store.finishEditing();
2349
            status.terminate();
2350
        } catch (Exception ex) {
2351
            LOGGER.warn("", ex);
2352
            status.abort();
2353
            throw new RuntimeException("", ex);
2354
        } finally {
2355
            IOUtils.closeQuietly(fis);
2356
            FeatureStore.cancelEditingQuietly(store);
2357
            DisposeUtils.disposeQuietly(store);
2358
            status.pop();
2359
        }
2360
    }
2361
    
2362
    @Override
2363
    public int download(String name, Envelope workingArea, SimpleTaskStatus status) {
2364
        I18nManager i18n = ToolsLocator.getI18nManager();
2365
        if (status == null) {
2366
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(i18n.getTranslation("_Downloading_data"));
2367
            status.setAutoremove(true);
2368
            status.add();
2369
        } else {
2370
            status.push();
2371
        }
2372
        FeatureStore store = null;
2373
        try {
2374
            status.message(i18n.getTranslation("_Downloading_data"));
2375
            status.setIndeterminate();
2376
            TilesCalculator tiles = new TilesCalculator();
2377
            OnlineEntity entity = this.getEntity(name);
2378
            List<Envelope> envs = tiles.calculateEnvelopes(
2379
                    entity.getTileSize(),
2380
                    Collections.singletonList(workingArea.getGeometry())
2381
            );
2382
            OnlineLayer layer = this.project.getLayer((OnlineLayer t) -> StringUtils.equalsIgnoreCase(t.getName(), name), status);
2383
            store = this.openFeatureStore(entity);
2384
            this.addStoreIgnoreChanges(store);
2385
            store.edit(FeatureStore.MODE_APPEND, FeatureStore.SUBMODE_MERGE);
2386
            GeometryManager geomManager = GeometryLocator.getGeometryManager();
2387
            IProjection layerProjection = layer.getProjection();
2388
            String geometryName = store.getDefaultFeatureTypeQuietly().getDefaultGeometryAttributeName();
2389
            int nenv = 0;
2390
            for (Envelope env : envs) {
2391
                nenv++;
2392
                status.message(i18n.getTranslation("_Downloading_data_from_area")+" "+nenv+"/"+envs.size()+" ");
2393
                for (Iterator<JsonObject> it = layer.getData(env, 5000, status); it.hasNext();) {
2394
                    if( status.isCancellationRequested() ) {
2395
                        status.cancel();
2396
                        throw new UserCancelTaskException();
2397
                    }
2398
                    JsonObject feature_online_json = it.next();
2399
                    JsonObject feature_desktop_json = convertOnlineToDesktopFeature(feature_online_json, geometryName, geomManager, layerProjection);
2400
                    if(feature_desktop_json == null){
2401
                        continue;
2402
                    }
2403
                    EditableFeature feature = store.createNewFeature(feature_desktop_json);
2404
                    store.insert(feature);
2405
//                    
2406
//                    EditableFeature feature = null;
2407
//                    Geometry geom = null;
2408
//                    JsonObject properties = feature_json.getJsonObject("properties");
2409
//                    JsonObject geom_json = feature_json.getJsonObject("geometry");
2410
//                    if( geom_json!=null ) {
2411
//                        geom = geomManager.createFrom(geom_json);
2412
//                        if( geom.getProjection()==null ) {
2413
//                            geom.setProjection(layer.getProjection());
2414
//                        }
2415
//                    }
2416
//                    if( properties==null ) {
2417
//                        if( geom == null ) {
2418
//                            continue;
2419
//                        }
2420
//                        feature = store.createNewFeature();                        
2421
//                    } else {
2422
//                        feature = store.createNewFeature(properties);
2423
//                    }
2424
//                    feature.setDefaultGeometry(geom);
2425
//                    store.insert(feature); // Insert or replace
2426
                }
2427
            }
2428
            status.setIndeterminate();
2429
            status.message(i18n.getTranslation("_Writing_data"));
2430
            store.finishEditing();
2431
            status.terminate();
2432
        } catch(UserCancelTaskException ex) {
2433
            throw ex;
2434
        } catch (Exception ex) {
2435
            LOGGER.warn("", ex);
2436
            status.abort();
2437
            throw new RuntimeException("", ex);
2438
        } finally {
2439
            this.removeStoreIgnoreChanges(store);
2440
            FeatureStore.cancelEditingQuietly(store);
2441
            DisposeUtils.disposeQuietly(store);
2442
            status.pop();
2443
        }
2444
        return 0;
2445
    }
2446
    
2447
    private JsonObject convertOnlineToDesktopFeature(JsonObject online_json, String geometryName, GeometryManager geomManager, IProjection proj) {
2448
        Geometry geom = null;
2449
        JsonObject properties = online_json.getJsonObject("properties");
2450
        JsonObject geom_json = online_json.getJsonObject("geometry");
2451
        if (geom_json != null) {
2452
            try {
2453
                geom = geomManager.createFrom(geom_json);
2454
            } catch (Exception ex) {
2455
            }
2456
            if (geom != null && geom.getProjection() == null) {
2457
                geom.setProjection(proj);
2458
            }
2459
        }
2460
        if (properties == null) {
2461
            if (geom == null) {
2462
                return null;
2463
            }
2464
            JsonObjectBuilder builder = Json.createObjectBuilder();
2465
            builder.add(geometryName, geom.convertToHexWKBQuietly());
2466
            return builder.build();
2467
        }
2468
        JsonObjectBuilder builder = Json.createObjectBuilder();
2469
        if (geom == null) {
2470
            builder.addNull(geometryName);
2471
        } else {
2472
            builder.add(geometryName, geom.convertToHexWKBQuietly());
2473
        }
2474
        builder.addAll(properties);
2475
        return builder.build();
2476
    }
2477

    
2478
    public boolean isAResourceTable(String entityName) {
2479
        // Deberia comprobar gvsigd_resources?
2480
        return false;
2481
    }
2482

    
2483
    @Override
2484
    public boolean canUpload() {
2485
        return canUpload(null);
2486
    }
2487

    
2488
    @Override
2489
    public boolean canUpload(MutableObject<String> message) {
2490
        return canUpload(message, null);
2491
    }
2492

    
2493
    @Override
2494
    public boolean canUpload(MutableObject<String> message, List<String> entityCodes) {
2495
        if( this.isOffline() ) {
2496
            return false;
2497
        }
2498
        I18nManager i18n = ToolsLocator.getI18nManager();
2499
        if (entityCodes == null) {
2500
            LOGGER.warn("entityCodes is null");
2501
            if (message != null) {
2502
                String msg = i18n.getTranslation("_It_is_mandatory_to_indicate_the_tables_on_which_you_want_to_commit");
2503
                message.setValue(msg);
2504
            }
2505
            return false;
2506
        }
2507
        return true;
2508
//        List<String> outdatedEntityNames = new ArrayList<>();
2509
//        WorkspaceChangesTable changesTable = new WorkspaceChangesTable();
2510
//        DisposableFeatureSetIterable changesGroupedByEntity = null;
2511
//        try {
2512
//            Set<String> repositoryCodes = new HashSet<>();
2513
//            repositoryCodes.add(this.getRepository().getCode());
2514
//            for (String entityCode : entityCodes) {
2515
//                EntityRow entity = this.getWorkspaceEntity(entityCode);
2516
//                int maskStatus = entity.getState();
2517
//                if( (maskStatus & STATE_CORRUPT) == STATE_CORRUPT ) {
2518
//                    LOGGER.info("Entity '"+entity.getEntityName()+"' marked as corrupt.");
2519
//                    if (message != null) {
2520
//                        String msg = i18n.getTranslation("_Some_of_the_selected_tables_are_marked_as_corrupt")
2521
//                                + ". (" + entity.getEntityName() + ")";
2522
//                        message.setValue(msg);
2523
//                    }
2524
//                    return false;
2525
//                }
2526
//                if( (maskStatus & STATE_DISCONNECTED) == STATE_DISCONNECTED ) {
2527
//                    LOGGER.info("Entity '"+entity.getEntityName()+"' marked as disconnected.");
2528
//                    if (message != null) {
2529
//                        String msg = i18n.getTranslation("_Some_of_the_selected_tables_are_marked_as_disconnected")
2530
//                                + ". (" + entity.getEntityName() + ")";
2531
//                        message.setValue(msg);
2532
//                    }
2533
//                    return false;
2534
//                }
2535
//                if( entity.isLinkedTable() ) {
2536
//                    VCSGisRepository linkedRepo = entity.getLinkedRepository();
2537
//                    if( linkedRepo!=null ) {
2538
//                        repositoryCodes.add(linkedRepo.getCode());
2539
//                    }
2540
//                }
2541
//            }
2542
//            if( repositoryCodes.size() > 1 ) {
2543
//                LOGGER.info("Too many repositories, only one allowed in commit.");
2544
//                if (message != null) {
2545
//                    String msg = i18n.getTranslation("_Too_many_repositories_only_one_allowed");
2546
//                    message.setValue(msg);
2547
//                }
2548
//                return false;
2549
//            }
2550
//            changesGroupedByEntity = changesTable.getGroupedByEntity(this);
2551
//            for (Feature fchange : changesGroupedByEntity) {
2552
//                WorkspaceChangeRow change = new WorkspaceChangeRow(this, fchange);
2553
//                VCSGisWorkspaceEntity entity = change.getEntity();
2554
//                if(entity == null){
2555
//                    continue;
2556
//                }
2557
//                if(CollectionUtils.isEmpty(entityCodes) || entityCodes.contains(entity.getEntityCode())){
2558
//                    LOGGER.debug("===: CAN-COMMIT: add used entity = " + fchange.toJson().toString().replace('\n', ' '));
2559
//                    if (change.isSelected() && entity.isOutdated()) {
2560
//                        outdatedEntityNames.add(entity.getEntityName());
2561
//                    }
2562
//                }
2563
//                
2564
//                switch (this.getEditMode(entity)) {
2565
//                    case FeatureStore.MODE_UNKNOWN:
2566
//                        // La tabla no existe en la copia de trabajo
2567
//                        LOGGER.info("Can access to '"+entity.getEntityName()+"'.");
2568
//                        if (message != null) {
2569
//                            String msg = i18n.getTranslation("_Some_of_the_selected_tables_are_damaged")
2570
//                                    + ". ("
2571
//                                    + entity.getEntityName()
2572
//                                    + ")";
2573
//                            message.setValue(msg);
2574
//                        }
2575
//                        return false;
2576
//                    case FeatureStore.MODE_FULLEDIT:
2577
//                    case FeatureStore.MODE_APPEND:
2578
//                    case FeatureStore.MODE_PASS_THROUGH:
2579
//                        LOGGER.info("Table '"+entity.getEntityName()+"' is editing.");
2580
//                        if (message != null) {
2581
//                            String msg = i18n.getTranslation("_Selected_tables_are_editing")
2582
//                                    + ". ("
2583
//                                    + entity.getEntityName()
2584
//                                    + ")";
2585
//                            message.setValue(msg);
2586
//                        }
2587
//
2588
//                        return false;
2589
//                }
2590
//
2591
//            }
2592
//            DisposeUtils.dispose(changesGroupedByEntity);
2593
//
2594
//            if (!outdatedEntityNames.isEmpty()) {
2595
//                LOGGER.info("Somme tables in working copy are outdated ("+StringUtils.join(outdatedEntityNames, ",")+").");
2596
//                if (message != null) {
2597
//                    String msg = i18n.getTranslation("_Tables_in_working_copy_are_outdated")
2598
//                            + ". ("
2599
//                            + StringUtils.join(outdatedEntityNames, ", ")
2600
//                            + ")";
2601
//                    message.setValue(msg);
2602
//                }
2603
//                return false;
2604
//            }
2605
//            return true;
2606
//        } catch (Exception ex) {
2607
//            LOGGER.warn("You cannot check that a commit can be done", ex);
2608
//            if (message != null) {
2609
//                String msg = i18n.getTranslation("_You_cannot_check_that_a_commit_can_be_done");
2610
//                message.setValue(msg);
2611
//            }
2612
//            return false;
2613
//        } finally {
2614
//            DisposeUtils.dispose(changesGroupedByEntity);
2615
//        }
2616
    }
2617

    
2618
    @Override
2619
    public int removeRemoteChanges(String entityCode) {
2620
        return removeRemoteChanges(entityCode, null);
2621
    }
2622

    
2623
    @Override
2624
    public int removeRemoteChanges(String entityCode, SimpleTaskStatus status) {
2625
        OnlineEntity entity = this.getEntity(entityCode);
2626
        if (entity == null) {
2627
            return ERR_ENTITY_NOT_EXISTS;
2628
        }
2629
        if (status == null) {
2630
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(
2631
                    "Update-clean " + entity.getEntityName()
2632
            );
2633
            status.setAutoremove(true);
2634
            status.add();
2635
        } else {
2636
            status.push();
2637
        }
2638
        FeatureStore remoteChangesStore = null;
2639
        FeatureStore localChangesStore = null;
2640
        FeatureStore entitiesStore = null;
2641
        try {
2642
            status.message("Deleting temporary remote changes (" + entity.getEntityName() + ")");
2643
            remoteChangesStore = openFeatureStore(RemoteChangesTable.TABLE_NAME, false);
2644
            localChangesStore = openFeatureStore(WorkspaceChangesTable.TABLE_NAME, false);
2645
            entitiesStore = openFeatureStore(EntitiesTable.TABLE_NAME, false);
2646
            removeRemoteChanges(remoteChangesStore, localChangesStore, entitiesStore, (EntityRow)entity);
2647
            status.message("Delete temporary remote changes completed");
2648
            status.terminate();
2649
            return ERR_OK;
2650
        } catch (Exception ex) {
2651
            LOGGER.warn("Can't deleting temporary remote changes of " + entity.getEntityName() + ".", ex);
2652
            status.message("Can't deleting temporary remote changes of " + entity.getEntityName() + ".");
2653
            status.abort();
2654
            return ERR_CANT_UPDATE_CLEAN;
2655
        } finally {
2656
            status.pop();
2657
            DisposeUtils.dispose(remoteChangesStore);
2658
            DisposeUtils.dispose(localChangesStore);
2659
            DisposeUtils.dispose(entitiesStore);
2660
        }
2661

    
2662
    }
2663
    
2664
    private void removeRemoteChanges(FeatureStore remoteChangesStore, FeatureStore localChangesStore, FeatureStore entitiesStore, EntityRow entity) throws DataException {
2665
        RemoteChangesTable remoteChangesTable = new RemoteChangesTable();
2666
        remoteChangesTable.delete(remoteChangesStore, entity.getEntityCode());
2667
        WorkspaceChangesTable localChangesTable = new WorkspaceChangesTable();
2668
        localChangesTable.changeState(localChangesStore, entity.getEntityCode(), STATE_CONFLICT, STATE_LOCAL_UNMODIFIED);
2669
        if(entity.getState() == STATE_CONFLICT){
2670
            entity.setState(STATE_LOCAL_MODIFIED);
2671
            boolean needFinish = false;
2672
            if(entitiesStore.getMode() == FeatureStore.MODE_QUERY){
2673
                entitiesStore.edit(MODE_PASS_THROUGH);
2674
                needFinish = true;
2675
            }
2676
            entity.update(entitiesStore);
2677
            if(needFinish){
2678
                entitiesStore.finishEditing();
2679
            }
2680
        }
2681
    }
2682

    
2683
    @Override
2684
    public boolean canUpdate(MutableObject<String> message, String tableName) {
2685
        if( this.isOffline() ) {
2686
            return false;
2687
        }
2688
        I18nManager i18n = ToolsLocator.getI18nManager();
2689
        EntityRow lentity = this.getWorkspaceEntityByName(tableName);
2690
        if (lentity == null) {
2691
            if (message != null) {
2692
                String msg = i18n.getTranslation("_Cant_update_table_XtablaX_dont_exists",new String[] {tableName});
2693
                message.setValue(msg);
2694
            }
2695
            return false;
2696
        }
2697
        switch (this.getEditMode(lentity)) {
2698
            case FeatureStore.MODE_UNKNOWN:
2699
                // La tabla no existe en la copia de trabajo
2700
                if (message != null) {
2701
                    String msg = i18n.getTranslation("_Cant_update_table_XtablaX_dont_exists",new String[] {tableName});
2702
                    message.setValue(msg);
2703
                }
2704
                return false;
2705

    
2706
            case FeatureStore.MODE_FULLEDIT:
2707
            case FeatureStore.MODE_APPEND:
2708
            case FeatureStore.MODE_PASS_THROUGH:
2709
                LOGGER.info("Table '"+lentity.getEntityName()+"' is editing.");
2710
                if (message != null) {
2711
                    String msg = i18n.getTranslation("_Cant_update_table_XtablaX_are_in_edition",new String[] {tableName});
2712
                    message.setValue(msg);
2713
                }
2714
                return false;
2715
        }
2716
        return true;
2717
    }
2718
    
2719
    private int getEditMode(OnlineEntity entity) {
2720
        FeatureStore userStore = null;
2721
        try {
2722
            userStore = this.openFeatureStore(entity);
2723
            if( userStore == null ) {
2724
                return FeatureStore.MODE_UNKNOWN;
2725
            }
2726
            return FeatureStoreObserver.getEditMode(userStore);
2727
        } finally {
2728
            DisposeUtils.dispose(userStore);
2729
        }
2730

    
2731
    }
2732
    
2733

    
2734
    @Override
2735
    public boolean updateNeedMerge(String entityName) {
2736
        if( this.isOffline() ) {
2737
            return false;
2738
        }
2739
        RemoteChangesTable remoteChangesTable = new RemoteChangesTable();
2740

    
2741
        OnlineEntity entity = this.getWorkspaceEntity(entityName);
2742

    
2743
        return remoteChangesTable.updateNeedMerge(this, entity.getEntityCode());
2744
    }
2745

    
2746
    @Override
2747
    public int update(String tableName, SimpleTaskStatus status) {
2748
        return this.update(tableName, false, status);
2749
    }
2750
    
2751
    public int update(String tableName, boolean merge, SimpleTaskStatus status) {
2752
        return update(tableName, merge, null, status);
2753
    }
2754

    
2755
    public int update(String tableName, boolean merge, MutableLong localChangesModifieds, SimpleTaskStatus status) {
2756
        if( this.isOffline() ) {
2757
            return ERR_OFFLINE;
2758
        }
2759
        if(localChangesModifieds == null){
2760
            localChangesModifieds = new MutableLong(0);
2761
        }
2762
        int errcode = ERR_NO_ERROR;
2763
        if (status == null) {
2764
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(
2765
                    "Update " + tableName
2766
            );
2767
            status.setAutoremove(true);
2768
            status.add();
2769
        } else {
2770
            status.push();
2771
        }
2772
        LOGGER.debug("===: UPDATE " + this.getCode() + ", '" + this.getLabel() + "', " + tableName);
2773
        RemoteChangesTable remoteChangesTable = new RemoteChangesTable();
2774
        WorkspaceChangesTable localChangesTable = new WorkspaceChangesTable();
2775

    
2776
        EditableFeature ef;
2777
        DisposableFeatureSetIterable remoteChanges = null;
2778

    
2779
        FeatureStore workspaceChangesStore = null;
2780
        FeatureStore remoteChangesStore = null;
2781
        FeatureStore userStore = null;
2782
        FeatureStore entitiesStore = null;
2783

    
2784
        DataTransaction transaction = null;
2785
        try {
2786
            if( status.isCancellationRequested() ) {
2787
                throw new UserCancelTaskException();
2788
            }
2789
            transaction = DALLocator.getDataManager().createTransaction();
2790
            transaction.begin();
2791

    
2792
            entitiesStore = this.openFeatureStore(EntitiesTable.TABLE_NAME, true);
2793
            transaction.add(entitiesStore);
2794
            entitiesStore.edit(MODE_PASS_THROUGH);
2795

    
2796
            EntityRow lentity = (EntityRow) this.getWorkspaceEntityByName(tableName);
2797
            if (!merge) {
2798
                status.message("Checking the need to merge");
2799
                if (remoteChangesTable.updateNeedMerge(this, lentity.getEntityCode())) {
2800
                    status.message("Can't update without merge.");
2801
                    status.abort();
2802
                    return ERR_UPDATE_NEED_MERGE;
2803
                }
2804
            }
2805
            String dataCodeFieldName = lentity.getFeatureIdFieldName();
2806
            status.message("Searching remote changes (" + lentity.getEntityName() + ")");
2807

    
2808
            userStore = this.openFeatureStore(lentity);
2809
            if (userStore == null) {
2810
                this.create_table(lentity);
2811
                userStore = this.openFeatureStore(lentity);
2812
            }
2813
            transaction.add(userStore);
2814
            userStore.edit(MODE_PASS_THROUGH);
2815

    
2816
            workspaceChangesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME,true);
2817
            transaction.add(workspaceChangesStore);
2818
            workspaceChangesStore.edit(MODE_PASS_THROUGH);
2819

    
2820
            remoteChangesStore = this.openFeatureStore(RemoteChangesTable.TABLE_NAME,true);
2821
            transaction.add(remoteChangesStore);
2822
            remoteChangesStore.edit(MODE_PASS_THROUGH);
2823

    
2824
            remoteChanges = remoteChangesTable.getSelectedsByEntityCodeAsIterator(this, lentity.getCode());
2825
            transaction.add(remoteChanges);
2826
//            long sz = ContainerUtils.size64(remoteChanges);
2827
//            status.setRangeOfValues(0, sz);
2828
            status.setCurValue(0);
2829

    
2830
            if (!remoteChanges.isEmpty()) {
2831
                this.addStoreIgnoreChanges(userStore);
2832
                status.message("Updating table (" + lentity.getEntityName() + ")");
2833
                FeatureType type = userStore.getDefaultFeatureTypeQuietly();
2834

    
2835
                ExpressionEvaluatorManager expManager = ExpressionEvaluatorLocator.getManager();
2836
                ExpressionBuilder builder = expManager.createExpressionBuilder();
2837
                
2838
                JsonObject dataJson;
2839
                FilteredLogger log = new FilteredLogger(LOGGER, "update", 100);
2840

    
2841
                for (Feature feature : remoteChanges) {
2842
                    if( status.isCancellationRequested() ) {
2843
                        throw new UserCancelTaskException();
2844
                    }
2845
                    RemoteChangeRow remoteChangeRow = new RemoteChangeRow(this, feature);
2846
                    switch (remoteChangeRow.getOperation()) {
2847
                        case OP_INSERT:
2848
                            LOGGER.debug("===: UPDATE: insert");
2849
                            switch (remoteChangeRow.getStatus()) {
2850
                                case STATE_CONFLICT:
2851
                                    DisposableFeatureSetIterable feats = getUserFeaturesConflictWithRemoteChange(lentity, remoteChangeRow, userStore);
2852
                                    if (feats != null) {
2853
                                        for (Feature feat : feats) {
2854
                                            if (feat != null) {
2855
                                                feats.getFeatureSet().delete(feat);
2856
                                                workspaceChangesStore.delete("\"" + WorkspaceChangesTable.FEATUREID + "\" = '" + feat.getString(lentity.getFeatureIdFieldName()) + "'");
2857
                                            }
2858
                                        }
2859
                                        DisposeUtils.disposeQuietly(feats);
2860
                                    }
2861
                                //Don't break to do the default case
2862
                                default:
2863
                                    dataJson = remoteChangeRow.getRelatedFeatureDataAsJson();
2864
                                    if( dataJson==null ) {
2865
                                        log.warn("A feature (VCSGISCODE="+remoteChangeRow.getRelatedFeatureCode()+") has been retrieved with the DAT_DATA field set to null.");
2866
                                    } else {
2867
                                        ef = userStore.createNewFeature(dataJson);
2868
                                        userStore.insert(ef);
2869
                                    }
2870
                                    break;
2871
                            }
2872
                            break;
2873
                        case OP_UPDATE:
2874
                            LOGGER.debug("===: UPDATE: update");
2875
                            dataJson = remoteChangeRow.getRelatedFeatureDataAsJson();
2876
                            if( dataJson==null ) {
2877
                                log.warn("A feature (VCSGISCODE="+remoteChangeRow.getRelatedFeatureCode()+") has been retrieved with the DAT_DATA field set to null.");
2878
                                break;
2879
                            }
2880
                            builder.set(null);
2881
                            for (FeatureAttributeDescriptor attr : type.getPrimaryKey()) {
2882
                                builder.and(
2883
                                        builder.eq(
2884
                                                builder.column(attr.getName()),
2885
                                                builder.constant(
2886
                                                        Json.toObject(dataJson.get(attr.getName()))
2887
                                                )
2888
                                        )
2889
                                );
2890
                            }
2891
                            Feature f = userStore.findFirst(builder.toString());
2892
                            if (f == null) {
2893
                                WorkspaceChangeRow localChange = localChangesTable.find(this, workspaceChangesStore, lentity.getEntityCode(), remoteChangeRow.getRelatedFeatureCode());
2894
                                if(localChange != null){
2895
                                    if(localChange.getOperation() == OP_DELETE){
2896
                                        ef = userStore.createNewFeature(dataJson);
2897
                                        userStore.insert(ef);
2898
                                        break;
2899
                                    } else {
2900
                                        throw new NullPointerException("Can't update null feature (" + builder.toString() + ").");
2901
                                    }
2902
                                } else { //Si me llega un update y no tengo la feature en el userStore ni tengo borrado local, es porque deberia ser un insert
2903
                                    //NOTA: !OJO! esto es porque algunas bases de datos nos devuelven un update en lugar de un insert
2904
                                    ef = userStore.createNewFeature(dataJson);
2905
                                    userStore.insert(ef);
2906
                                    break;
2907
                                }
2908
                            }
2909
                            ef = f.getEditable();
2910
                            ef.copyFrom(dataJson);
2911
                            if( removeMissingValues(ef,dataJson) ) {
2912
                                // kill the admin
2913
                                log.warn("Missing attributes in the json (kill the admin?)");
2914
                            }
2915
                            userStore.update(ef);
2916
//                            workspaceChangesStore.delete("\"" + WorkspaceChangesTable.FEATUREID + "\"='" + remoteChangeRow.getRelatedFeatureCode()+ "'");
2917
                            break;
2918

    
2919
                        case OP_DELETE:
2920
                            LOGGER.debug("===: UPDATE: delete");
2921
                            userStore.delete("\"" + dataCodeFieldName + "\"='" + remoteChangeRow.getRelatedFeatureCode() + "'");
2922
//                            workspaceChangesStore.delete("\"" + WorkspaceChangesTable.FEATUREID + "\"='" + remoteChangeRow.getRelatedFeatureCode()+ "'");
2923
                            break;
2924
                    }
2925
                    status.incrementCurrentValue();
2926
                }
2927
            }
2928

    
2929
            if (merge) {
2930
                status.message("Searching local changes to merge (" + lentity.getEntityName() + ")");
2931
                DisposeUtils.disposeQuietly(remoteChanges);
2932
                remoteChanges = remoteChangesTable.getNotSelectedsByEntityCodeAsIterator(this, lentity.getCode());
2933
                transaction.add(remoteChanges);
2934
//                sz = ContainerUtils.size64(remoteChanges);
2935
//                status.setRangeOfValues(0, sz);
2936
                status.setCurValue(0);
2937

    
2938
                if (!remoteChanges.isEmpty()) {
2939
                    //We edit the changesStore because we will need local changes 
2940
//                    workspaceChangesStore.edit(MODE_PASS_THROUGH);
2941

    
2942
                    //We edit the destination store because we may need to update some features (in case OP_DELETE)
2943
//                    userStore.edit(MODE_PASS_THROUGH);
2944
                    this.addStoreIgnoreChanges(userStore);
2945

    
2946
                    status.message("Adding to local changes (" + lentity.getEntityName() + ")");
2947
                    for (Feature feature : remoteChanges) {
2948
                        if( status.isCancellationRequested() ) {
2949
                            throw new UserCancelTaskException();
2950
                        }
2951
                        RemoteChangeRow remoteChangeRow = new RemoteChangeRow(this, feature);
2952
                        Feature f = userStore.findFirst("\"" + lentity.getFeatureIdFieldName() + "\" = " + remoteChangeRow.getRelatedFeatureCode());
2953
                        switch (remoteChangeRow.getOperation()) {
2954
                            case OP_INSERT:
2955
                                LOGGER.debug("===: UPDATE: insert");
2956
                                if (f == null) {
2957
                                    LOGGER.debug("===: UPDATE: add delete operation to RelatedFeatureCode "+remoteChangeRow.getRelatedFeatureCode());
2958
                                    this.addDeleteChange(null, lentity, workspaceChangesStore, remoteChangeRow.getRelatedFeatureCode(), null, null);
2959
                                } else {
2960
                                    LOGGER.debug("===: UPDATE: add update operation to RelatedFeatureCode "+remoteChangeRow.getRelatedFeatureCode());
2961
                                    this.addChange(null, lentity, OP_UPDATE, workspaceChangesStore, f, feature, null);
2962
                                }
2963
                                localChangesModifieds.increment();
2964
                                break;
2965

    
2966
                            case OP_UPDATE:
2967
                                LOGGER.debug("===: UPDATE: update");
2968
                                if (f == null) {
2969
                                    LOGGER.debug("===: UPDATE: add delete operation to RelatedFeatureCode "+remoteChangeRow.getRelatedFeatureCode());
2970
                                    this.addDeleteChange(null, lentity, workspaceChangesStore, remoteChangeRow.getRelatedFeatureCode(), null, null);
2971
                                } else {
2972
                                    LOGGER.debug("===: UPDATE: add update operation to RelatedFeatureCode "+remoteChangeRow.getRelatedFeatureCode());
2973
                                    this.addChange(null, lentity, OP_UPDATE, workspaceChangesStore, f, feature,null);
2974
                                }
2975
                                localChangesModifieds.increment();
2976
                                break;
2977
                            case OP_DELETE:
2978
                                LOGGER.debug("===: UPDATE: delete");
2979
                                if (f != null) {
2980
                                    userStore.delete("\"" + dataCodeFieldName + "\"=" + remoteChangeRow.getRelatedFeatureCode());
2981
                                    ef = userStore.createNewFeature(f);
2982
                                    String localEntityName = lentity.getEntityName();
2983
                                    long newRelatedFeatureCode = this.createUniqueCodeLong(localEntityName);
2984
                                    ef.setLong(lentity.getFeatureIdFieldName(), newRelatedFeatureCode);
2985
                                    userStore.insert(ef);
2986

    
2987
                                    workspaceChangesStore.delete("\"" + WorkspaceChangesTable.FEATUREID + "\"=" + remoteChangeRow.getRelatedFeatureCode());
2988
                                    LOGGER.debug("===: UPDATE: add insert operation to RelatedFeatureCode " + newRelatedFeatureCode);
2989
                                    this.addChange(null, lentity, OP_INSERT, workspaceChangesStore, ef, null, null);
2990
                                    localChangesModifieds.increment();
2991
                                } else {
2992
                                    // Ha habido un delete remoto. Si habia tambien un
2993
                                    // delete en local del mismo elemento borramos el delete local.
2994
                                    this.removeLocalDeleteIfExists(remoteChangeRow.getRelatedFeatureCode(), workspaceChangesStore);
2995
                                    localChangesModifieds.increment();
2996
                                }
2997
                                break;
2998
                        }
2999
                        status.incrementCurrentValue();
3000
                    }
3001
                }
3002
            }
3003
            localChangesTable.removeLocalChangesRelatedToSelectedRemoteChanges(this, lentity);
3004
            remoteChangesTable.delete(remoteChangesStore, lentity.getEntityCode());
3005

    
3006
            status.message("Updating metadata tables");
3007
            if( !this.isCorrupt(lentity, userStore, 0, false) ) {
3008
                lentity.updateState(transaction);
3009
            }
3010
            lentity.update(entitiesStore);
3011
            
3012
            transaction.commit();
3013
            forceReloadWorkspaceEntities();
3014

    
3015
            status.message("Update completed");
3016
            status.terminate();
3017
            return ERR_OK;
3018
        } catch (UserCancelTaskException ex) {
3019
            LOGGER.warn("User cancelled.", ex);
3020
            status.message("User cancelled");
3021
            status.cancel();
3022
            DataTransaction.rollbackQuietly(transaction);
3023
            throw new UserCancelTaskException();
3024
        } catch (Exception ex) {
3025
            LOGGER.warn("Can't update.", ex);
3026
            status.message("Can't update");
3027
            status.abort();
3028
            return ERR_CANT_UPDATE;
3029
        } finally {
3030
            this.removeStoreIgnoreChanges(userStore);
3031
            DisposeUtils.disposeQuietly(transaction);
3032
            status.pop();
3033
        }
3034
    }
3035

    
3036
    private DisposableFeatureSetIterable getUserFeaturesConflictWithRemoteChange(OnlineEntity lentity, RemoteChangeRow remoteChange, FeatureStore store) throws DataException {
3037
        if (store == null) {
3038
            return null;
3039
        }
3040
        FeatureType featType = lentity.getFeatureType();
3041
        JsonObject data = remoteChange.getRelatedFeatureDataAsJson();
3042
        ExpressionEvaluatorManager expManager = ExpressionEvaluatorLocator.getManager();
3043
        ExpressionBuilder builder = expManager.createExpressionBuilder();
3044
        builder.set(null);
3045
        for (FeatureAttributeDescriptor attr : featType) {
3046
            if (StringUtils.equalsAnyIgnoreCase(lentity.getFeatureIdFieldName(), attr.getName())) {
3047
                continue;
3048
            }
3049
            if (attr.isIndexed() && !attr.allowIndexDuplicateds()) {
3050
                Object value = Json.toObject(data, attr.getName());
3051
                builder.or(
3052
                        builder.eq(
3053
                                builder.column(attr.getName()),
3054
                                builder.constant(value)
3055
                        )
3056
                );
3057
            }
3058
        }
3059
        ExpressionBuilder.Value value = builder.value();
3060
        if (value == null) {
3061
            return null;
3062
        }
3063
        ExpressionBuilder.BinaryOperator filter = builder.and(
3064
                builder.not(
3065
                        builder.eq(
3066
                                builder.column(lentity.getFeatureIdFieldName()),
3067
                                builder.constant(remoteChange.getRelatedFeatureCode())
3068
                        )
3069
                ),
3070
                value
3071
        );
3072

    
3073
        FeatureSet feats = store.getFeatureSet(filter.toString());
3074
        return feats.iterable();
3075
    }
3076

    
3077
    private boolean removeMissingValues(EditableFeature ef, JsonObject dataJson) {
3078
        boolean hasMissingValues = false;
3079
        try {
3080
            FeatureType ftype = ef.getType();
3081
            for (FeatureAttributeDescriptor attr : ftype) {
3082
                if( !dataJson.containsKey(attr.getName()) ) {
3083
                    if( attr.allowNull() && attr.isReadOnly() && !attr.isPrimaryKey() ) {
3084
                        ef.set(attr.getName(), null);
3085
                        hasMissingValues = true;
3086
                    }
3087
                }
3088
            }
3089
            return hasMissingValues;
3090
        } catch(Exception e) {
3091
            LOGGER.debug("Can't remove missing values",e);
3092
            // Do nothing
3093
        }
3094
        return hasMissingValues;
3095
    }
3096

    
3097
    private void removeLocalDeleteIfExists(long relatedFeatureCode, FeatureStore changesStore) {
3098
        try {
3099
            // El store esta en modo PASS-THROUGH, asi que lanzamos el delete directamente.
3100
            changesStore.delete(
3101
                "\""+WorkspaceChangesTable.FEATUREID + "\" = " + relatedFeatureCode + " AND "+
3102
                "\""+WorkspaceChangesTable.OPERATION + "\" = "+OP_DELETE
3103
            );
3104
        } catch(Exception e) {
3105
            throw new RuntimeException("Can't delete local-delete if exists", e);
3106
        }
3107
    }
3108
    
3109

    
3110
    @Override
3111
    public int merge(String tableName, MutableLong localChangesCreated, SimpleTaskStatus status) {
3112
        return this.update(tableName, true, localChangesCreated, status);
3113
    }
3114

    
3115
    @Override
3116
    public int synchronize(OnlineEntity entity, Envelope workingArea, SimpleTaskStatus status) {
3117
        I18nManager i18n = ToolsLocator.getI18nManager();
3118
        if (status == null) {
3119
            status = ToolsLocator.getTaskStatusManager().createDefaultSimpleTaskStatus(i18n.getTranslation("_Synchronizing"));
3120
            status.setAutoremove(true);
3121
            status.add();
3122
        } else {
3123
            status.push();
3124
        }
3125

    
3126
        status.setIndeterminate();
3127
        status.message(entity.getEntityName());
3128
        
3129
        WorkspaceChangesTable wct = new WorkspaceChangesTable();
3130
        Iterator<Geometry> geoms = null;
3131
        Iterator<Geometry> geoms2 = null;
3132
        FeatureStore remoteStore = null;
3133
        FeatureStore localStore = null;
3134
        FeatureSet remoteSet = null;
3135
        DisposableIterator<Feature> remoteIt = null;
3136
        FeatureSet localSet = null;
3137
        DisposableIterator<Feature> localIt = null;
3138

    
3139
        FeatureStore localChangesStore = null;
3140
        FeatureStore remoteChangesStore = null;
3141
        FeatureStore entitiesStore = null;
3142
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
3143
        
3144
        try {
3145
            OnlineWorkspaceImpl wc = this;
3146
            DisposableFeatureSetIterable it = wct.getSelectedsByEntityCodeAsIterator(this, entity.getEntityCode());
3147
            geoms = new Iterator<Geometry>() {
3148
                @Override
3149
                public boolean hasNext() {
3150
                    return it.hasNext();
3151
                }
3152

    
3153
                @Override
3154
                public Geometry next() {
3155
                    Feature f = it.next();
3156
                    WorkspaceChangeRow row = new WorkspaceChangeRow(wc, f);
3157
                    if (row.getOperation() == OP_DELETE) {
3158
                        return null;
3159
                    }
3160
                    return row.getRelatedFeature().getDefaultGeometry();
3161
                }
3162
            };
3163

    
3164
            DisposableFeatureSetIterable it2 = wct.getSelectedsByEntityCodeAsIterator(this, entity.getEntityCode());
3165
            geoms2 = new Iterator<Geometry>() {
3166
                @Override
3167
                public boolean hasNext() {
3168
                    return it2.hasNext();
3169
                }
3170

    
3171
                @Override
3172
                public Geometry next() {
3173
                    try {
3174
                        Feature f = it2.next();
3175
                        WorkspaceChangeRow row = new WorkspaceChangeRow(wc, f);
3176
                        
3177
                        JsonObject dataAsJson = row.getDataAsJson();
3178
                        if(dataAsJson == null){
3179
                            return null;
3180
                        }
3181
                        String geom_wkb = dataAsJson.getString(entity.getGeometryFieldName());
3182
                        if(geom_wkb == null) {
3183
                            return null;
3184
                        }
3185
                        return geomManager.createFrom(geom_wkb);
3186
                    } catch (GeometryException ex) {
3187
                        LOGGER.warn("Can't get geometry of workspace change", ex);
3188
                        return null;
3189
                    }
3190
                }
3191
            };
3192

    
3193
            TilesCalculator tilesCalculator = new TilesCalculator();
3194
            List<Envelope> envs = tilesCalculator.calculateEnvelopes(
3195
                entity.getTileSize(), 
3196
                new ChainedIterator<>(
3197
                    geoms, 
3198
                    geoms2, 
3199
                    workingArea == null?Collections.EMPTY_LIST.iterator():Collections.singletonList(workingArea.getGeometry()).iterator()
3200
                )
3201
            );
3202

    
3203
            OnlineLayer layer = this.project.getLayer(
3204
                (OnlineLayer t) -> StringUtils.equals(t.getName(), entity.getEntityName()),
3205
                SimpleTaskStatus.FAKE_STATUS
3206
            );
3207
            File f = ((HasAFile) this.getExplorerParameters()).getFile();
3208
            String tmpPathname = H2SpatialUtils.removeH2FileNameExtension(f.getAbsolutePath())+"_tmp_"+entity.getEntityName();
3209
//            File tmpRemote = new File(tmpPathname);
3210
            File tmpRemote = ToolsLocator.getFoldersManager().getUniqueFile(tmpPathname);
3211
            DataManager dataManager = DALLocator.getDataManager();
3212
            DataServerExplorerParameters expParameters = DALLocator.getDataManager().createServerExplorerParameters(FeatureStore.H2SPATIAL_PROVIDER_NAME);
3213
            ((HasAFile) expParameters).setFile(tmpRemote);
3214
            DataServerExplorer explorer = dataManager.openServerExplorer(FeatureStore.H2SPATIAL_PROVIDER_NAME, expParameters);
3215
            JDBCNewStoreParameters params = (JDBCNewStoreParameters) explorer.getAddParameters(entity.getEntityName());
3216
            EditableFeatureType ft = params.getDefaultFeatureType();
3217
            ft.add(FEATURECODE_FIELD_NAME, DataTypes.INT).setIsPrimaryKey(true);
3218
            ft.add(FEATUREVERSION_FIELD_NAME, DataTypes.INT);
3219
            ft.add("feature", DataTypes.STRING, DataManager.RECOMENDED_SIZE_FOR_CLOB);
3220
            explorer.add(FeatureStore.H2SPATIAL_PROVIDER_NAME, params, true);
3221
            DataStoreParameters storeParams = explorer.get(entity.getEntityName());
3222
            remoteStore = (FeatureStore) dataManager.openStore(FeatureStore.H2SPATIAL_PROVIDER_NAME, storeParams);
3223
            remoteStore.edit(FeatureStore.MODE_APPEND, FeatureStore.SUBMODE_MERGE);
3224

    
3225
            String geometryName = entity.getFeatureType().getDefaultGeometryAttributeName();
3226
            IProjection layerProj = entity.getCRSAsProjection();
3227
            for (Envelope env : envs) {
3228
                Iterator<JsonObject> data = layer.getData(env, 1000, status);
3229
                while (data.hasNext()) {
3230
                    if(status.isCancellationRequested()){
3231
                        throw new UserCancelTaskException();
3232
                    }
3233
                    JsonObject json = data.next();
3234
                    JsonObject properties_json = json.getJsonObject("properties");
3235
                    EditableFeature feat = remoteStore.createNewFeature();
3236
                    feat.set(FEATURECODE_FIELD_NAME, properties_json.getInt(FEATURECODE_FIELD_NAME, 0));
3237
                    feat.set(FEATUREVERSION_FIELD_NAME, properties_json.getInt(FEATUREVERSION_FIELD_NAME, 0));
3238
                    feat.set("feature", convertOnlineToDesktopFeature(json, geometryName, geomManager, layerProj).toString());
3239
                    remoteStore.insert(feat);
3240
                }
3241
            }
3242
            remoteStore.finishEditing();
3243

    
3244
            localChangesStore = this.openFeatureStore(WorkspaceChangesTable.TABLE_NAME, true);
3245
            remoteChangesStore = this.openFeatureStore(RemoteChangesTable.TABLE_NAME, true);
3246
            entitiesStore = this.openFeatureStore(EntitiesTable.TABLE_NAME, true);
3247
            final FeatureStore finalLocalChangesStore = localChangesStore;
3248
            final FeatureStore finalRemoteChangesStore = remoteChangesStore;
3249

    
3250
            removeRemoteChanges(remoteChangesStore, localChangesStore, entitiesStore, (EntityRow)entity);
3251
            
3252
            remoteChangesStore.edit(FeatureStore.MODE_APPEND);
3253
            localChangesStore.edit(FeatureStore.MODE_PASS_THROUGH);
3254
            
3255
            PatchGenerator.PatchHandler<Feature> handler = new PatchGenerator.PatchHandler<Feature>() {
3256
                WorkspaceChangeRow lastLocalChange = null;
3257
                
3258
                @Override
3259
                public int compareId(Feature r, Feature l) {
3260
                    return Integer.compare(r.getInt(FEATURECODE_FIELD_NAME), l.getInt(FEATURECODE_FIELD_NAME));
3261
                }
3262

    
3263
                @Override
3264
                public boolean isNew(Feature l) {
3265
                    return l.getInt(FEATURECODE_FIELD_NAME) < 0;
3266
                }
3267

    
3268
                @Override
3269
                public boolean isLocalChange(Feature l) {
3270
                    lastLocalChange = wct.find(wc, finalLocalChangesStore, entity.getEntityCode(), l.getInt(FEATURECODE_FIELD_NAME));
3271
                    return lastLocalChange != null;
3272
                }
3273

    
3274
                @Override
3275
                public boolean isRemoteChange(Feature r, Feature l) {
3276
                    return r.getInt(FEATUREVERSION_FIELD_NAME) != l.getInt(FEATUREVERSION_FIELD_NAME);
3277
                }
3278

    
3279
                @Override
3280
                public void addRemoteChangeDelete(Feature l, boolean conflict) {
3281
                    RemoteChangeRow row = new RemoteChangeRow(wc);
3282
                    row.setData(l.toJson().toString());
3283
                    row.setEntityCode(entity.getEntityCode());
3284
                    row.setOperation(OP_DELETE);
3285
                    row.setRevisionNumber(l.getInt(FEATUREVERSION_FIELD_NAME));
3286
                    row.setSelected(true);
3287
                    row.setStatus(conflict ? STATE_CONFLICT : STATE_LOCAL_UNMODIFIED);
3288
                    row.setRelatedFeatureCode(l.getInt(FEATURECODE_FIELD_NAME));
3289
                    row.setCode(createUniqueCode());
3290
                    row.insert(finalRemoteChangesStore);
3291
                    if (conflict) {
3292
                        if (lastLocalChange == null
3293
                            || !(lastLocalChange.getEntityCode().equals(row.getEntityCode())
3294
                            && lastLocalChange.getRelatedFeatureCode() == row.getRelatedFeatureCode())) {
3295

    
3296
                            lastLocalChange = wct.find(wc, finalLocalChangesStore, entity.getEntityCode(), l.getInt(FEATURECODE_FIELD_NAME));
3297
                        }
3298
                        if(lastLocalChange != null && lastLocalChange.getStatus() != STATE_CONFLICT) {
3299
                            lastLocalChange.setStatus(STATE_CONFLICT);
3300
                            lastLocalChange.update(finalLocalChangesStore);
3301
                        }
3302
                        ((EntityRow)entity).setState(STATE_CONFLICT);
3303
                    }
3304
                }
3305

    
3306
                @Override
3307
                public void addRemoteChangeModify(Feature r, boolean conflict) {
3308
                    RemoteChangeRow row = new RemoteChangeRow(wc);
3309
                    row.setData(r.getString("feature"));
3310
                    row.setEntityCode(entity.getEntityCode());
3311
                    row.setOperation(OP_UPDATE);
3312
                    row.setRevisionNumber(r.getInt(FEATUREVERSION_FIELD_NAME));
3313
                    row.setSelected(true);
3314
                    row.setStatus(conflict ? STATE_CONFLICT : STATE_LOCAL_UNMODIFIED);
3315
                    row.setRelatedFeatureCode(r.getInt(FEATURECODE_FIELD_NAME));
3316
                    row.setCode(createUniqueCode());
3317
                    row.insert(finalRemoteChangesStore);
3318
                    if (conflict) {
3319
                        if (lastLocalChange == null
3320
                            || !(lastLocalChange.getEntityCode().equals(row.getEntityCode())
3321
                            && lastLocalChange.getRelatedFeatureCode() == r.getInt(FEATURECODE_FIELD_NAME))) {
3322

    
3323
                            lastLocalChange = wct.find(wc, finalLocalChangesStore, entity.getEntityCode(), r.getInt(FEATURECODE_FIELD_NAME));
3324
                        }
3325
                        if(lastLocalChange != null && lastLocalChange.getStatus() != STATE_CONFLICT) {
3326
                            lastLocalChange.setStatus(STATE_CONFLICT);
3327
                            lastLocalChange.update(finalLocalChangesStore);
3328
                        }
3329
                        ((EntityRow)entity).setState(STATE_CONFLICT);
3330
                    }
3331
                }
3332

    
3333
                @Override
3334
                public void addRemoteChangeInsert(Feature r) {
3335
                    RemoteChangeRow row = new RemoteChangeRow(wc);
3336
                    row.setData(r.getString("feature"));
3337
                    row.setEntityCode(entity.getEntityCode());
3338
                    row.setOperation(OP_INSERT);
3339
                    row.setRevisionNumber(r.getInt(FEATUREVERSION_FIELD_NAME));
3340
                    row.setSelected(true);
3341
                    row.setStatus(STATE_LOCAL_UNMODIFIED);
3342
                    row.setCode(createUniqueCode());
3343
                    row.insert(finalRemoteChangesStore);
3344
                }
3345
            };
3346

    
3347
            PatchGenerator<Feature> patchGenerator = PatchGenerator.create(handler);
3348

    
3349
            localStore = this.openFeatureStore(entity);
3350
            remoteSet = remoteStore.getFeatureSet((String) null, FEATURECODE_FIELD_NAME);
3351
            remoteIt = remoteSet.fastIterator();
3352
            GeometryExpressionBuilder expBuilder = (GeometryExpressionBuilder) localStore.createExpressionBuilder();
3353
            FeatureType localStoreFt = localStore.getDefaultFeatureTypeQuietly();
3354
            String geomName = localStoreFt.getDefaultGeometryAttributeName();
3355
            IProjection localStoreProj = localStoreFt.getDefaultSRS();
3356
            for (Envelope env : envs) {
3357
                expBuilder.or(
3358
                    expBuilder.ST_Intersects(
3359
                        expBuilder.column(geomName),
3360
                        expBuilder.envelope(env, localStoreProj)
3361
                    )
3362
                );
3363
            }
3364
            localSet = localStore.getFeatureSet(expBuilder.build(), FEATURECODE_FIELD_NAME);
3365
            localIt = localSet.fastIterator();
3366
            
3367
            patchGenerator.generate(remoteIt,localIt, status);
3368
            remoteChangesStore.finishEditing();
3369
            localChangesStore.finishEditing();
3370
            status.terminate();
3371
            return ERR_OK;
3372

    
3373
        } catch (UserCancelTaskException ex) {
3374
            FeatureStore.cancelEditingQuietly(remoteStore);
3375
            FeatureStore.cancelEditingQuietly(remoteChangesStore);
3376
            FeatureStore.cancelEditingQuietly(localChangesStore);
3377
            status.cancel();
3378
            return ERR_CANCELLED_BY_USER;
3379
        } catch (Exception ex) {
3380
            LOGGER.warn("Can't synchronize", ex);
3381
            FeatureStore.cancelEditingQuietly(remoteStore);
3382
            FeatureStore.cancelEditingQuietly(remoteChangesStore);
3383
            FeatureStore.cancelEditingQuietly(localChangesStore);
3384
            status.abort();
3385
            return ERR_SYNCHRONIZE;
3386
        } finally {
3387
            status.pop();
3388

    
3389
            DisposeUtils.disposeQuietly(geoms);
3390

    
3391
            DisposeUtils.disposeQuietly(remoteChangesStore);
3392
            DisposeUtils.disposeQuietly(localChangesStore);
3393

    
3394
            DisposeUtils.disposeQuietly(remoteIt);
3395
            DisposeUtils.disposeQuietly(remoteSet);
3396
            DisposeUtils.disposeQuietly(remoteStore);
3397
            
3398
            DisposeUtils.disposeQuietly(localIt);
3399
            DisposeUtils.disposeQuietly(localSet);
3400
            DisposeUtils.disposeQuietly(localStore);
3401
            
3402
            DisposeUtils.disposeQuietly(entitiesStore);
3403
            
3404
        }
3405
    }
3406

    
3407
    @Override
3408
    public WorkingArea getCurrentWorkingArea() {
3409
        return this.currentWorkingArea;
3410
    }
3411

    
3412
    @Override
3413
    public void setCurrentWorkingArea(WorkingArea workingArea) {
3414
        this.currentWorkingArea = workingArea;
3415
        VarsTable varsTable = new VarsTable();
3416
        varsTable.set(this, CONFIG_CURRENT_WORKINGAREA, workingArea.toJson().toString());
3417
    }
3418
    
3419
    private void refreshCodeGeneratorSequence(String entityName) {
3420
        OnlineEntity entity = this.getWorkspaceEntity(entityName);
3421
        long sequence = 0;
3422
        FeatureStore store = null;
3423
        try {
3424
            store = this.openFeatureStore(entity);
3425
            FeatureQuery query = store.createFeatureQuery();
3426
            query.addAggregate("MIN", entity.getFeatureIdFieldName());
3427
            Feature f = store.findFirst(query);
3428
            long l = f.getLong(entity.getFeatureIdFieldName());
3429
            if (sequence > l) {
3430
                sequence = l;
3431
            }
3432
        } catch (Exception ex) {
3433
            LOGGER.warn("Can't refresh code generator sequence");
3434
        } finally {
3435
            DisposeUtils.dispose(store);
3436
        }
3437
        this.codeGenerator.initSequence(entityName, sequence-1);
3438
    }
3439

    
3440
}
3441