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

History | View | Annotate | Download (15.2 KB)

1 45445 jjdelcerro
/*
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 47673 jjdelcerro
import java.util.Collection;
27 45650 jjdelcerro
import java.util.HashMap;
28 47606 fdiaz
import java.util.HashSet;
29 45445 jjdelcerro
import java.util.List;
30 45650 jjdelcerro
import java.util.Map;
31 47606 fdiaz
import java.util.Set;
32 45445 jjdelcerro
import java.util.UUID;
33 46160 jjdelcerro
import org.apache.commons.lang3.StringUtils;
34 47217 fdiaz
import org.apache.commons.lang3.tuple.MutablePair;
35
import org.apache.commons.lang3.tuple.Pair;
36 45482 fdiaz
import org.gvsig.fmap.dal.DataServerExplorer;
37 45445 jjdelcerro
import org.gvsig.fmap.dal.DataStore;
38 45650 jjdelcerro
import org.gvsig.fmap.dal.SupportTransactions;
39 45445 jjdelcerro
import org.gvsig.fmap.dal.exception.DataException;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41 45482 fdiaz
import static org.gvsig.fmap.dal.feature.FeatureStore.MODE_QUERY;
42 45650 jjdelcerro
import org.gvsig.fmap.dal.spi.DataTransactionServices;
43 45445 jjdelcerro
import org.gvsig.tools.dispose.Disposable;
44
import org.gvsig.tools.dispose.DisposeUtils;
45 47188 fdiaz
import org.gvsig.tools.dispose.impl.AbstractDisposable;
46 46315 jjdelcerro
import org.gvsig.tools.observer.BaseNotification;
47
import org.gvsig.tools.observer.ObservableHelper;
48
import org.gvsig.tools.observer.Observer;
49 46230 jjdelcerro
import org.slf4j.Logger;
50
import org.slf4j.LoggerFactory;
51 45445 jjdelcerro
52
/**
53
 *
54
 * @author gvSIG Team
55
 */
56
@SuppressWarnings("UseSpecificCatch")
57 47188 fdiaz
public class DefaultTransaction extends AbstractDisposable implements DataTransactionServices {
58 45445 jjdelcerro
59 46230 jjdelcerro
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultTransaction.class);
60
61 45445 jjdelcerro
    private final String code;
62 46160 jjdelcerro
    private final Map<String,DataServerExplorer> explorers;
63 45650 jjdelcerro
    private final Map<String,ConnectionService> connections;
64 47217 fdiaz
    private Map<String,Pair<DataStore,Boolean>> stores;
65 45445 jjdelcerro
    private boolean inProgress;
66
    private List<Disposable> disposables;
67 46315 jjdelcerro
    private ObservableHelper observableHelper;
68 47606 fdiaz
    private Set<SupportTransactions> supportTransactions;
69 45445 jjdelcerro
70
    public DefaultTransaction() {
71
        this.code = UUID.randomUUID().toString().replace("-", "");
72 46160 jjdelcerro
        this.stores = new HashMap<>();
73
        this.explorers = new HashMap<>();
74 45445 jjdelcerro
        this.disposables = new ArrayList<>();
75 47606 fdiaz
        this.supportTransactions = new HashSet<>();
76 45445 jjdelcerro
        this.inProgress = false;
77 45650 jjdelcerro
        this.connections = new HashMap<>();
78 46315 jjdelcerro
        this.observableHelper = new ObservableHelper();
79 45445 jjdelcerro
    }
80
81
    @Override
82
    public String getCode() {
83
        return this.code;
84
    }
85
86
    @Override
87
    public void begin() throws DataException {
88 45650 jjdelcerro
        if( this.inProgress ) {
89
            throw new IllegalStateException("Transaction already started.");
90
        }
91 46315 jjdelcerro
        this.observableHelper.notifyObservers(this, new BaseNotification("BEGIN", null));
92 45445 jjdelcerro
        this.inProgress = true;
93
    }
94
95
    @Override
96
    public void commit() throws DataException {
97 47673 jjdelcerro
        if (!this.isInProgress()) {
98 46125 fdiaz
            throw new IllegalStateException("Can't commit transaction without begin.");
99 45445 jjdelcerro
        }
100 47673 jjdelcerro
        try {
101
            LOGGER.debug("commit in "+this.getCode());
102
            int retries = 5;
103
            boolean needretry = false;
104
            while(retries > 0) {
105
                needretry = false;
106
                Collection<Pair<DataStore, Boolean>> theStores = new ArrayList(stores.values());
107
                for (Pair<DataStore, Boolean> item : theStores) {
108
                    DataStore store = getStore(item);
109
                    if (store instanceof FeatureStore) {
110
                        FeatureStore fstore = (FeatureStore) store;
111
                        if (fstore != null && fstore.getMode() != MODE_QUERY) {
112
                            LOGGER.debug("commit: finishEditing "+store.getFullName());
113
                            fstore.finishEditing();
114
                            needretry=true;
115
                        }
116
                    }
117 45445 jjdelcerro
                }
118 47673 jjdelcerro
                if( !needretry ) {
119
                    break;
120
                }
121
                LOGGER.debug("commit: retry store finish editing");
122
                retries--;
123 45445 jjdelcerro
            }
124 47673 jjdelcerro
            for (ConnectionService connection : this.connections.values()) {
125
                connection.finish();
126
            }
127
            this.observableHelper.notifyObservers(this, new BaseNotification("COMMIT", null));
128
            this.inProgress = false;
129
        } finally {
130
            LOGGER.debug("commit out "+this.getCode());
131 45445 jjdelcerro
        }
132
    }
133
134
    @Override
135
    public void rollback() throws DataException {
136
        if( !this.isInProgress() ) {
137 46125 fdiaz
            throw new IllegalStateException("Can't rollback transaction without begin.");
138 45445 jjdelcerro
        }
139 47673 jjdelcerro
//        LOGGER.info("rollback in");
140 47217 fdiaz
        for (Pair<DataStore, Boolean> item : stores.values()) {
141 47328 jjdelcerro
            DataStore store = getStore(item);
142 45445 jjdelcerro
            if( store instanceof FeatureStore ) {
143
                FeatureStore fstore = (FeatureStore) store;
144 45482 fdiaz
                if( fstore.getMode() != MODE_QUERY) {
145 45445 jjdelcerro
                    fstore.cancelEditing();
146
                }
147
            }
148
        }
149 46315 jjdelcerro
        for (ConnectionService connection : this.connections.values()) {
150
            connection.abort();
151
        }
152
        this.observableHelper.notifyObservers(this, new BaseNotification("ROLLBACK", null));
153 45445 jjdelcerro
        this.inProgress = false;
154 47673 jjdelcerro
//        LOGGER.info("rollback out");
155 45445 jjdelcerro
    }
156
157
    @Override
158
    public void rollbackQuietly() {
159
        try {
160
            this.rollback();
161
        } catch(Exception ex) {
162
            // Do nothing
163
        }
164
    }
165
166
    @Override
167
    public void add(DataStore store) {
168 46160 jjdelcerro
        add(store, null, true);
169 45482 fdiaz
    }
170
171
    @Override
172 46160 jjdelcerro
    public void add(DataStore store, String id) {
173
        this.add(store, id, true);
174
    }
175
176
    @Override
177 45482 fdiaz
    public void add(DataStore store, boolean local) {
178 46160 jjdelcerro
        this.add(store, null, local);
179
    }
180
181
    @Override
182
    public void add(DataStore store, String id, boolean local) {
183 47673 jjdelcerro
        if (store == null) {
184 47606 fdiaz
            throw new IllegalArgumentException("The store is required.");
185
        }
186 47673 jjdelcerro
//        try {
187
//            LOGGER.info("add in "+this.getCode()+" "+store.getFullName());
188
            String theId = id;
189
            if (StringUtils.isBlank(id)) {
190
                theId = store.hashCode() + "@" + store.getFullName();
191
            } else {
192
                DataStore theStore = getStore(this.stores.get(theId));
193
                if (theStore != null) {
194
                    if (theStore == store) {
195
                        return;
196
                    }
197
                    throw new IllegalArgumentException("The id '" + id + "' is already used.");
198 46160 jjdelcerro
                }
199
            }
200 47673 jjdelcerro
            if (store instanceof SupportTransactions) {
201
                ((SupportTransactions) store).setTransaction(this);
202
            }
203
            if (!local) {
204
                DisposeUtils.bind(store);
205
            }
206
            this.stores.put(theId, new MutablePair<>(store, local));
207
//        } finally {
208
//            LOGGER.info("add out");
209
//        }
210 45445 jjdelcerro
    }
211
212
    @Override
213 46160 jjdelcerro
    public FeatureStore getFeatureStore(String id) {
214 47779 fdiaz
        FeatureStore store = (FeatureStore) this.getStore(this.stores.get(id));
215
        if(store == null){
216
            for (Pair<DataStore, Boolean> value : stores.values()) {
217
                DataStore currentStore = this.getStore(value);
218
                if(StringUtils.equalsIgnoreCase(id, currentStore.getName())){
219
                    if(store != null){
220
                        if(!StringUtils.equals(store.getFullName(), currentStore.getFullName())){
221
                            return null;
222
                        }
223
                    }
224
                    store = (FeatureStore) this.getStore(value);
225
                }
226
            }
227
        }
228
        return store;
229 46160 jjdelcerro
    }
230
231
    @Override
232 45482 fdiaz
    public void add(DataServerExplorer explorer) {
233 46160 jjdelcerro
        this.add(explorer, null, true);
234 45482 fdiaz
    }
235
236
    @Override
237 46160 jjdelcerro
    public void add(DataServerExplorer explorer, String id) {
238
        this.add(explorer, id, true);
239
    }
240
241
    @Override
242 45482 fdiaz
    public void add(DataServerExplorer explorer, boolean local) {
243 46160 jjdelcerro
        this.add(explorer, null, local);
244
    }
245
246
    @Override
247
    public void add(DataServerExplorer explorer, String id, boolean local) {
248 47606 fdiaz
        if(explorer == null){
249
            throw new IllegalArgumentException("The explorer is required.");
250
        }
251 46160 jjdelcerro
        String theId = id;
252
        if( StringUtils.isBlank(id) ) {
253
            theId = String.valueOf(explorer.hashCode());
254
        } else {
255
            DataServerExplorer theExplorer = this.explorers.get(theId);
256
            if(theExplorer!=null ){
257
                if( theExplorer==explorer ) {
258
                    return;
259
                }
260
                throw new IllegalArgumentException("The id '"+id+"' is already used.");
261
            }
262 45482 fdiaz
        }
263 46160 jjdelcerro
264 45650 jjdelcerro
        if( explorer instanceof SupportTransactions ) {
265
            ((SupportTransactions) explorer).setTransaction(this);
266
        }
267 45482 fdiaz
        if(!local){
268
            DisposeUtils.bind(explorer);
269
        }
270 46160 jjdelcerro
        this.explorers.put(theId,explorer);
271 45482 fdiaz
    }
272 46160 jjdelcerro
273
    @Override
274
    public DataServerExplorer getServerExplorer(String id) {
275
        return this.explorers.get(id);
276
    }
277 45482 fdiaz
278
    @Override
279 45445 jjdelcerro
    public void add(Disposable resource) throws DataException {
280
        this.disposables.add(resource);
281
    }
282
283
    @Override
284 47606 fdiaz
    public void add(SupportTransactions obj, boolean local) throws DataException {
285
        if(obj == null){
286
            throw new IllegalArgumentException("The transaction supplier is required.");
287
        }
288
        if(obj instanceof DataStore){
289
          this.add((DataStore)obj, local);
290
          return;
291
        }
292
        if(obj instanceof DataServerExplorer){
293
          this.add((DataServerExplorer)obj, local);
294
          return;
295
        }
296
        obj.setTransaction(this);
297
        if(!local){
298
            DisposeUtils.bind(obj);
299
        }
300
        this.supportTransactions.add(obj);
301
    }
302
303
    @Override
304 45445 jjdelcerro
    public void remove(DataStore store) {
305 47217 fdiaz
        if( this.inProgress && !DisposeUtils.isNullOrDisposed(store)){
306 45445 jjdelcerro
            throw new IllegalStateException("Can't remove store from a in progress transaction.");
307
        }
308 47673 jjdelcerro
//        try {
309
//            LOGGER.info("remove in");
310
            String id = null;
311
            for (Map.Entry<String, Pair<DataStore,Boolean>> entry : this.stores.entrySet()) {
312
                if( store == getStore(entry.getValue()) ) {
313
                    id = entry.getKey();
314
                    break;
315
                }
316 46160 jjdelcerro
            }
317 47673 jjdelcerro
            if( id==null ) {
318
                return;
319
            }
320
            if( store instanceof SupportTransactions ) {
321
                ((SupportTransactions) store).setTransaction(null);
322
            }
323
            this.stores.remove(id);
324
            DisposeUtils.dispose(store);
325
//        } finally {
326
//            LOGGER.info("remove in");
327
//        }
328 45445 jjdelcerro
    }
329
330
    @Override
331 46160 jjdelcerro
    public void remove(DataServerExplorer serverExplorer) {
332
        if( this.inProgress ) {
333
            throw new IllegalStateException("Can't remove server explorer from a in progress transaction.");
334
        }
335
        String id = null;
336
        for (Map.Entry<String, DataServerExplorer> entry : this.explorers.entrySet()) {
337
            if( serverExplorer == entry.getValue() ) {
338
                id = entry.getKey();
339
                break;
340
            }
341
        }
342
        if( id==null ) {
343
            return;
344
        }
345
        if( serverExplorer instanceof SupportTransactions ) {
346
            ((SupportTransactions) serverExplorer).setTransaction(null);
347
        }
348
        this.explorers.remove(id);
349
        DisposeUtils.dispose(serverExplorer);
350
    }
351
352
    @Override
353 45445 jjdelcerro
    public boolean isInProgress() {
354
        return inProgress;
355
    }
356
357
    @Override
358 47188 fdiaz
    public void doDispose() {
359 47673 jjdelcerro
//        LOGGER.info("doDispose in "+this.getCode());
360
361 45445 jjdelcerro
        if( this.inProgress ) {
362
            this.rollbackQuietly();
363
        }
364 47217 fdiaz
        for (Pair<DataStore, Boolean> item : stores.values()) {
365 47328 jjdelcerro
            DataStore store = getStore(item);
366 45650 jjdelcerro
            if( store instanceof SupportTransactions ) {
367
                ((SupportTransactions) store).setTransaction(null);
368
            }
369 45445 jjdelcerro
            DisposeUtils.disposeQuietly(store);
370
371
        }
372 46160 jjdelcerro
        for (DataServerExplorer explorer : explorers.values()) {
373 45650 jjdelcerro
            if( explorer instanceof SupportTransactions ) {
374
                ((SupportTransactions) explorer).setTransaction(null);
375
            }
376 45482 fdiaz
            DisposeUtils.disposeQuietly(explorer);
377
378
        }
379 45445 jjdelcerro
        for (Disposable resource : disposables) {
380 45650 jjdelcerro
            if( resource instanceof SupportTransactions ) {
381
                ((SupportTransactions) resource).setTransaction(null);
382
            }
383 46315 jjdelcerro
            DisposeUtils.disposeQuietly(resource);
384 45445 jjdelcerro
        }
385 47606 fdiaz
        for (SupportTransactions obj : supportTransactions) {
386
            obj.setTransaction(null);
387
            DisposeUtils.disposeQuietly(obj);
388
        }
389 46315 jjdelcerro
        for (ConnectionService connection : this.connections.values()) {
390
            connection.dispose();
391
        }
392 47606 fdiaz
        this.supportTransactions = null;
393 45445 jjdelcerro
        this.disposables = null;
394
        this.stores = null;
395 47673 jjdelcerro
//        LOGGER.info("doDispose out");
396
   }
397 45445 jjdelcerro
398
    @Override
399
    public void close() throws Exception {
400
        this.dispose();
401
    }
402 45650 jjdelcerro
403
    @Override
404
    public void addConnection(ConnectionService connection) {
405
        if( this.connections.containsKey(connection.getId()) ) {
406
            return;
407
        }
408
        this.connections.put(connection.getId(), connection);
409
    }
410
411
    @Override
412
    public ConnectionService getConnection(String id) {
413
        return this.connections.get(id);
414
    }
415
416
    @Override
417
    public void removeConnection(String id) {
418
        this.connections.remove(id);
419
    }
420
421
    @Override
422
    public boolean existsConnection(String id) {
423
        return this.connections.containsKey(id);
424
    }
425 46315 jjdelcerro
426
    @Override
427
    public void addObserver(Observer obsrvr) {
428
        this.observableHelper.addObserver(obsrvr);
429
    }
430
431
    @Override
432
    public void deleteObserver(Observer obsrvr) {
433
        this.observableHelper.deleteObserver(obsrvr);
434
    }
435
436
    @Override
437
    public void deleteObservers() {
438
        this.observableHelper.deleteObservers();
439
    }
440 46316 fdiaz
441
    @Override
442
    public boolean contains(DataServerExplorer explorer) {
443
        for (DataServerExplorer value : this.explorers.values()) {
444
            if(explorer == value){
445
                return true;
446
            }
447
        }
448
        return false;
449
    }
450
451
    @Override
452
    public boolean contains(DataStore store) {
453 47217 fdiaz
        for (Pair<DataStore, Boolean> item : stores.values()) {
454 47328 jjdelcerro
            DataStore value = getStore(item);
455 46316 fdiaz
            if(store == value){
456
                return true;
457
            }
458
        }
459
        return false;
460
    }
461 47328 jjdelcerro
462
    private DataStore getStore(Pair<DataStore, Boolean> item) {
463
        if( item == null ) {
464
            return null;
465
        }
466
        return item.getLeft();
467
    }
468
469 45445 jjdelcerro
}