All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.controller.cluster.databroker.AbstractDOMBrokerTransaction Maven / Gradle / Ivy

/*
 * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.controller.cluster.databroker;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;

import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.common.api.TransactionDatastoreMismatchException;
import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransaction;
import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionFactory;

public abstract class AbstractDOMBrokerTransaction implements DOMDataTreeTransaction {

    private static final VarHandle BACKING_TX;

    static {
        try {
            BACKING_TX = MethodHandles.lookup()
                .findVarHandle(AbstractDOMBrokerTransaction.class, "backingTx", Entry.class);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    private final @NonNull Object identifier;
    private final Map storeTxFactories;

    private volatile Entry backingTx;

    /**
     * Creates new transaction.
     *
     * @param identifier Identifier of transaction.
     */
    protected AbstractDOMBrokerTransaction(final Object identifier,
            Map storeTxFactories) {
        this.identifier = requireNonNull(identifier, "Identifier should not be null");
        this.storeTxFactories = requireNonNull(storeTxFactories, "Store Transaction Factories should not be null");
        checkArgument(!storeTxFactories.isEmpty(), "Store Transaction Factories should not be empty");
    }

    /**
     * Returns sub-transaction associated with supplied key.
     *
     * @param datastoreType the data store type
     * @return the sub-transaction
     * @throws NullPointerException                  if datastoreType is null
     * @throws IllegalArgumentException              if no sub-transaction is associated with datastoreType.
     * @throws TransactionDatastoreMismatchException if datastoreType mismatches the one used at first access
     */
    protected final T getSubtransaction(final LogicalDatastoreType datastoreType) {
        requireNonNull(datastoreType, "datastoreType must not be null.");

        var entry = backingTx;
        if (entry == null) {
            if (!storeTxFactories.containsKey(datastoreType)) {
                throw new IllegalArgumentException(datastoreType + " is not supported");
            }
            final var tx = createTransaction(datastoreType);
            final var newEntry = Map.entry(datastoreType, tx);
            final var witness = (Entry) BACKING_TX.compareAndExchange(this, null, newEntry);
            if (witness != null) {
                tx.close();
                entry = witness;
            } else {
                entry = newEntry;
            }
        }

        final var expected = entry.getKey();
        if (expected != datastoreType) {
            throw new TransactionDatastoreMismatchException(expected, datastoreType);
        }
        return entry.getValue();
    }

    /**
     * Returns sub-transaction if initialized.
     */
    protected T getSubtransaction() {
        final Entry entry;
        return (entry = backingTx) == null ? null : entry.getValue();
    }

    protected abstract T createTransaction(LogicalDatastoreType datastoreType);

    @Override
    public Object getIdentifier() {
        return identifier;
    }

    @SuppressWarnings("checkstyle:IllegalCatch")
    protected void closeSubtransaction() {
        if (backingTx != null) {
            try {
                backingTx.getValue().close();
            } catch (Exception e) {
                throw new IllegalStateException("Uncaught exception occurred during closing transaction", e);
            }
        }
    }

    protected DOMStoreTransactionFactory getTxFactory(LogicalDatastoreType type) {
        return storeTxFactories.get(type);
    }

    @Override
    public final String toString() {
        return addToStringAttributes(MoreObjects.toStringHelper(this).omitNullValues()).toString();
    }

    protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
        return toStringHelper.add("identifier", identifier);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy