Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / impl / DefaultTransaction.java @ 47606

History | View | Annotate | Download (13.2 KB)

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

    
23
package org.gvsig.fmap.dal.impl;
24

    
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.util.HashSet;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.Set;
31
import java.util.UUID;
32
import org.apache.commons.lang3.StringUtils;
33
import org.apache.commons.lang3.tuple.MutablePair;
34
import org.apache.commons.lang3.tuple.Pair;
35
import org.gvsig.fmap.dal.DataServerExplorer;
36
import org.gvsig.fmap.dal.DataStore;
37
import org.gvsig.fmap.dal.SupportTransactions;
38
import org.gvsig.fmap.dal.exception.DataException;
39
import org.gvsig.fmap.dal.feature.FeatureStore;
40
import static org.gvsig.fmap.dal.feature.FeatureStore.MODE_QUERY;
41
import org.gvsig.fmap.dal.spi.DataTransactionServices;
42
import org.gvsig.tools.dispose.Disposable;
43
import org.gvsig.tools.dispose.DisposeUtils;
44
import org.gvsig.tools.dispose.impl.AbstractDisposable;
45
import org.gvsig.tools.observer.BaseNotification;
46
import org.gvsig.tools.observer.ObservableHelper;
47
import org.gvsig.tools.observer.Observer;
48
import org.slf4j.Logger;
49
import org.slf4j.LoggerFactory;
50

    
51
/**
52
 *
53
 * @author gvSIG Team
54
 */
55
@SuppressWarnings("UseSpecificCatch")
56
public class DefaultTransaction extends AbstractDisposable implements DataTransactionServices {
57

    
58
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultTransaction.class);
59
    
60
    private final String code;
61
    private final Map<String,DataServerExplorer> explorers;
62
    private final Map<String,ConnectionService> connections;
63
    private Map<String,Pair<DataStore,Boolean>> stores;
64
    private boolean inProgress;
65
    private List<Disposable> disposables;
66
    private ObservableHelper observableHelper;
67
    private Set<SupportTransactions> supportTransactions;
68

    
69
    public DefaultTransaction() {
70
        this.code = UUID.randomUUID().toString().replace("-", "");
71
        this.stores = new HashMap<>();
72
        this.explorers = new HashMap<>();
73
        this.disposables = new ArrayList<>();
74
        this.supportTransactions = new HashSet<>();
75
        this.inProgress = false;
76
        this.connections = new HashMap<>();
77
        this.observableHelper = new ObservableHelper();
78
    }
79

    
80
    @Override
81
    public String getCode() {
82
        return this.code;
83
    }
84

    
85
    @Override
86
    public void begin() throws DataException {
87
        if( this.inProgress ) {
88
            throw new IllegalStateException("Transaction already started.");
89
        }
90
        this.observableHelper.notifyObservers(this, new BaseNotification("BEGIN", null));
91
        this.inProgress = true;
92
    }
93

    
94
    @Override
95
    public void commit() throws DataException {
96
        if( !this.isInProgress() ) {
97
            throw new IllegalStateException("Can't commit transaction without begin.");
98
        }
99
        for (Pair<DataStore, Boolean> item : stores.values()) {
100
            DataStore store = getStore(item);
101
            if( store instanceof FeatureStore ) {
102
                FeatureStore fstore = (FeatureStore) store;
103
                if( fstore!=null && fstore.getMode() != MODE_QUERY) {
104
//                    LOGGER.info("Transaction commit: finishEditing "+store.getFullName());
105
                    fstore.finishEditing();
106
                }
107
            }
108
        }
109
        for (ConnectionService connection : this.connections.values()) {
110
            connection.finish();
111
        }
112
        this.observableHelper.notifyObservers(this, new BaseNotification("COMMIT", null));
113
        this.inProgress = false;
114
    }
115

    
116
    @Override
117
    public void rollback() throws DataException {
118
        if( !this.isInProgress() ) {
119
            throw new IllegalStateException("Can't rollback transaction without begin.");
120
        }
121
        
122
        for (Pair<DataStore, Boolean> item : stores.values()) {
123
            DataStore store = getStore(item);
124
            if( store instanceof FeatureStore ) {
125
                FeatureStore fstore = (FeatureStore) store;
126
                if( fstore.getMode() != MODE_QUERY) {
127
                    fstore.cancelEditing();
128
                }
129
            }
130
        }
131
        for (ConnectionService connection : this.connections.values()) {
132
            connection.abort();
133
        }
134
        this.observableHelper.notifyObservers(this, new BaseNotification("ROLLBACK", null));
135
        this.inProgress = false;
136
    }
137

    
138
    @Override
139
    public void rollbackQuietly() {
140
        try {
141
            this.rollback();
142
        } catch(Exception ex) {
143
            // Do nothing
144
        }
145
    }
146

    
147
    @Override
148
    public void add(DataStore store) {
149
        add(store, null, true);
150
    }
151

    
152
    @Override
153
    public void add(DataStore store, String id) { 
154
        this.add(store, id, true);
155
    }
156
    
157
    @Override
158
    public void add(DataStore store, boolean local) {
159
        this.add(store, null, local);
160
    }
161
    
162
    @Override
163
    public void add(DataStore store, String id, boolean local) {
164
        if(store == null){
165
            throw new IllegalArgumentException("The store is required.");
166
        }
167
        String theId = id;
168
        if( StringUtils.isBlank(id) ) {
169
            theId = store.hashCode() + "@"+ store.getFullName();
170
        } else {
171
            DataStore theStore = getStore(this.stores.get(theId));
172
            if(theStore!=null ){
173
                if( theStore==store ) {
174
                    return;
175
                }
176
                throw new IllegalArgumentException("The id '"+id+"' is already used.");
177
            }
178
        }
179
        if( store instanceof SupportTransactions ) {
180
            ((SupportTransactions) store).setTransaction(this);
181
        }
182
        if(!local){
183
            DisposeUtils.bind(store);
184
        }
185
        this.stores.put(theId,new MutablePair<>(store,local));
186
    }
187

    
188
    @Override
189
    public FeatureStore getFeatureStore(String id) {
190
        return (FeatureStore) this.getStore(this.stores.get(id));
191
    }
192
    
193
    @Override
194
    public void add(DataServerExplorer explorer) {
195
        this.add(explorer, null, true);
196
    }
197

    
198
    @Override
199
    public void add(DataServerExplorer explorer, String id) {
200
        this.add(explorer, id, true);
201
    }
202
    
203
    @Override
204
    public void add(DataServerExplorer explorer, boolean local) {
205
        this.add(explorer, null, local);
206
    }
207
    
208
    @Override
209
    public void add(DataServerExplorer explorer, String id, boolean local) {
210
        if(explorer == null){
211
            throw new IllegalArgumentException("The explorer is required.");
212
        }
213
        String theId = id;
214
        if( StringUtils.isBlank(id) ) {
215
            theId = String.valueOf(explorer.hashCode());
216
        } else {
217
            DataServerExplorer theExplorer = this.explorers.get(theId);
218
            if(theExplorer!=null ){
219
                if( theExplorer==explorer ) {
220
                    return;
221
                }
222
                throw new IllegalArgumentException("The id '"+id+"' is already used.");
223
            }
224
        }
225
        
226
        if( explorer instanceof SupportTransactions ) {
227
            ((SupportTransactions) explorer).setTransaction(this);
228
        }
229
        if(!local){
230
            DisposeUtils.bind(explorer);
231
        }
232
        this.explorers.put(theId,explorer);
233
    }
234
    
235
    @Override
236
    public DataServerExplorer getServerExplorer(String id) {
237
        return this.explorers.get(id);
238
    }
239

    
240
    @Override
241
    public void add(Disposable resource) throws DataException {
242
        this.disposables.add(resource);
243
    }
244

    
245
    @Override
246
    public void add(SupportTransactions obj, boolean local) throws DataException {
247
        if(obj == null){
248
            throw new IllegalArgumentException("The transaction supplier is required.");
249
        }
250
        if(obj instanceof DataStore){
251
          this.add((DataStore)obj, local);
252
          return;
253
        } 
254
        if(obj instanceof DataServerExplorer){
255
          this.add((DataServerExplorer)obj, local);
256
          return;
257
        } 
258
        obj.setTransaction(this);
259
        if(!local){
260
            DisposeUtils.bind(obj);
261
        }
262
        this.supportTransactions.add(obj);
263
    }
264

    
265
    @Override
266
    public void remove(DataStore store) {
267
        if( this.inProgress && !DisposeUtils.isNullOrDisposed(store)){
268
            throw new IllegalStateException("Can't remove store from a in progress transaction.");
269
        }
270
        String id = null;
271
        for (Map.Entry<String, Pair<DataStore,Boolean>> entry : this.stores.entrySet()) {
272
            if( store == getStore(entry.getValue()) ) {
273
                id = entry.getKey();
274
                break;
275
            }
276
        }
277
        if( id==null ) {
278
            return;
279
        }
280
        if( store instanceof SupportTransactions ) {
281
            ((SupportTransactions) store).setTransaction(null);
282
        }
283
        this.stores.remove(id);
284
        DisposeUtils.dispose(store);
285
    }
286

    
287
    @Override
288
    public void remove(DataServerExplorer serverExplorer) {
289
        if( this.inProgress ) {
290
            throw new IllegalStateException("Can't remove server explorer from a in progress transaction.");
291
        }
292
        String id = null;
293
        for (Map.Entry<String, DataServerExplorer> entry : this.explorers.entrySet()) {
294
            if( serverExplorer == entry.getValue() ) {
295
                id = entry.getKey();
296
                break;
297
            }
298
        }
299
        if( id==null ) {
300
            return;
301
        }
302
        if( serverExplorer instanceof SupportTransactions ) {
303
            ((SupportTransactions) serverExplorer).setTransaction(null);
304
        }
305
        this.explorers.remove(id);
306
        DisposeUtils.dispose(serverExplorer);
307
    }
308

    
309
    @Override
310
    public boolean isInProgress() {
311
        return inProgress;
312
    }
313

    
314
    @Override
315
    public void doDispose() {
316
        if( this.inProgress ) {
317
            this.rollbackQuietly();
318
        }
319
        for (Pair<DataStore, Boolean> item : stores.values()) {
320
            DataStore store = getStore(item);
321
            if( store instanceof SupportTransactions ) {
322
                ((SupportTransactions) store).setTransaction(null);
323
            }
324
            DisposeUtils.disposeQuietly(store);
325
            
326
        }
327
        for (DataServerExplorer explorer : explorers.values()) {
328
            if( explorer instanceof SupportTransactions ) {
329
                ((SupportTransactions) explorer).setTransaction(null);
330
            }
331
            DisposeUtils.disposeQuietly(explorer);
332
            
333
        }
334
        for (Disposable resource : disposables) {
335
            if( resource instanceof SupportTransactions ) {
336
                ((SupportTransactions) resource).setTransaction(null);
337
            }
338
            DisposeUtils.disposeQuietly(resource);            
339
        }
340
        for (SupportTransactions obj : supportTransactions) {
341
            obj.setTransaction(null);
342
            DisposeUtils.disposeQuietly(obj);            
343
        }
344
        for (ConnectionService connection : this.connections.values()) {
345
            connection.dispose();
346
        }
347
        this.supportTransactions = null;
348
        this.disposables = null;
349
        this.stores = null;
350
    }
351

    
352
    @Override
353
    public void close() throws Exception {
354
        this.dispose();
355
    }
356

    
357
    @Override
358
    public void addConnection(ConnectionService connection) {
359
        if( this.connections.containsKey(connection.getId()) ) {
360
            return;
361
        }
362
        this.connections.put(connection.getId(), connection);
363
    }
364

    
365
    @Override
366
    public ConnectionService getConnection(String id) {
367
        return this.connections.get(id);
368
    }
369

    
370
    @Override
371
    public void removeConnection(String id) {
372
        this.connections.remove(id);
373
    }
374

    
375
    @Override
376
    public boolean existsConnection(String id) {
377
        return this.connections.containsKey(id);
378
    }
379

    
380
    @Override
381
    public void addObserver(Observer obsrvr) {
382
        this.observableHelper.addObserver(obsrvr);
383
    }
384

    
385
    @Override
386
    public void deleteObserver(Observer obsrvr) {
387
        this.observableHelper.deleteObserver(obsrvr);
388
    }
389

    
390
    @Override
391
    public void deleteObservers() {
392
        this.observableHelper.deleteObservers();
393
    }
394

    
395
    @Override
396
    public boolean contains(DataServerExplorer explorer) {
397
        for (DataServerExplorer value : this.explorers.values()) {
398
            if(explorer == value){
399
                return true;
400
            }
401
        }
402
        return false;
403
    }
404

    
405
    @Override
406
    public boolean contains(DataStore store) {
407
        for (Pair<DataStore, Boolean> item : stores.values()) {
408
            DataStore value = getStore(item);
409
            if(store == value){
410
                return true;
411
            }
412
        }
413
        return false;
414
    }
415
    
416
    private DataStore getStore(Pair<DataStore, Boolean> item) {
417
        if( item == null ) {
418
            return null;
419
        }
420
        return item.getLeft();
421
    }
422
        
423
}