Adopt odlparent-10.0.0/yangtools-8.0.0-SNAPSHOT
[mdsal.git] / dom / mdsal-dom-broker / src / main / java / org / opendaylight / mdsal / dom / broker / DOMDataBrokerTransactionChainImpl.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.dom.broker;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import java.util.Collection;
17 import java.util.Map;
18 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
19 import java.util.concurrent.atomic.AtomicLong;
20 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
21 import org.opendaylight.mdsal.common.api.CommitInfo;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
24 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
25 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
26 import org.opendaylight.mdsal.dom.spi.store.DOMStoreThreePhaseCommitCohort;
27 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * NormalizedNode implementation of {@link org.opendaylight.mdsal.common.api.TransactionChain} which is backed
33  * by several {@link DOMStoreTransactionChain} differentiated by provided
34  * {@link org.opendaylight.mdsal.common.api.LogicalDatastoreType} type.
35  *
36  */
37 final class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTransactionFactory<DOMStoreTransactionChain>
38         implements DOMTransactionChain {
39     private enum State {
40         RUNNING,
41         CLOSING,
42         CLOSED,
43         FAILED,
44     }
45
46     private static final AtomicIntegerFieldUpdater<DOMDataBrokerTransactionChainImpl> COUNTER_UPDATER =
47             AtomicIntegerFieldUpdater.newUpdater(DOMDataBrokerTransactionChainImpl.class, "counter");
48     private static final AtomicReferenceFieldUpdater<DOMDataBrokerTransactionChainImpl, State> STATE_UPDATER =
49             AtomicReferenceFieldUpdater.newUpdater(DOMDataBrokerTransactionChainImpl.class, State.class, "state");
50     private static final Logger LOG = LoggerFactory.getLogger(DOMDataBrokerTransactionChainImpl.class);
51     private final AtomicLong txNum = new AtomicLong();
52     private final AbstractDOMDataBroker broker;
53     private final DOMTransactionChainListener listener;
54     private final long chainId;
55
56     private volatile State state = State.RUNNING;
57     private volatile int counter = 0;
58
59     /**
60      *Constructor with args.
61      *
62      * @param chainId
63      *            ID of transaction chain
64      * @param chains
65      *            Backing {@link DOMStoreTransactionChain}s.
66      * @param coordinator
67      *            Commit Coordinator which should be used to coordinate commits
68      *            of transaction
69      *            produced by this chain.
70      * @param listener
71      *            Listener, which listens on transaction chain events.
72      * @throws NullPointerException
73      *             If any of arguments is null.
74      */
75     DOMDataBrokerTransactionChainImpl(final long chainId,
76             final Map<LogicalDatastoreType, DOMStoreTransactionChain> chains,
77             final AbstractDOMDataBroker broker, final DOMTransactionChainListener listener) {
78         super(chains);
79         this.chainId = chainId;
80         this.broker = requireNonNull(broker);
81         this.listener = requireNonNull(listener);
82     }
83
84     private void checkNotFailed() {
85         Preconditions.checkState(state != State.FAILED, "Transaction chain has failed");
86     }
87
88     @Override
89     protected Object newTransactionIdentifier() {
90         return "DOM-CHAIN-" + chainId + "-" + txNum.getAndIncrement();
91     }
92
93     @Override
94     protected FluentFuture<? extends CommitInfo> commit(final DOMDataTreeWriteTransaction transaction,
95             final Collection<DOMStoreThreePhaseCommitCohort> cohorts) {
96         checkNotFailed();
97         checkNotClosed();
98
99         final FluentFuture<? extends CommitInfo> ret = broker.commit(transaction, cohorts);
100
101         COUNTER_UPDATER.incrementAndGet(this);
102         ret.addCallback(new FutureCallback<CommitInfo>() {
103             @Override
104             public void onSuccess(final CommitInfo result) {
105                 transactionCompleted();
106             }
107
108             @Override
109             public void onFailure(final Throwable throwable) {
110                 transactionFailed(transaction, throwable);
111             }
112         }, MoreExecutors.directExecutor());
113
114         return ret;
115     }
116
117     @Override
118     public void close() {
119         final boolean success = STATE_UPDATER.compareAndSet(this, State.RUNNING, State.CLOSING);
120         if (!success) {
121             LOG.debug("Chain {} is no longer running", this);
122             return;
123         }
124
125         super.close();
126         for (DOMStoreTransactionChain subChain : getTxFactories().values()) {
127             subChain.close();
128         }
129
130         if (counter == 0) {
131             finishClose();
132         }
133     }
134
135     private void finishClose() {
136         state = State.CLOSED;
137         listener.onTransactionChainSuccessful(this);
138     }
139
140     private void transactionCompleted() {
141         if (COUNTER_UPDATER.decrementAndGet(this) == 0 && state == State.CLOSING) {
142             finishClose();
143         }
144     }
145
146     private void transactionFailed(final DOMDataTreeWriteTransaction tx, final Throwable cause) {
147         state = State.FAILED;
148         LOG.debug("Transaction chain {} failed.", this, cause);
149         listener.onTransactionChainFailed(this, tx, cause);
150     }
151 }