org.opendaylight.mdsal.dom.spi.AbstractDOMForwardedTransaction Maven / Gradle / Ivy
Show all versions of mdsal-dom-spi Show documentation
/*
* Copyright (c) 2014 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.mdsal.dom.spi;
import static java.util.Objects.requireNonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
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;
/**
* Composite DOM Transaction backed by {@link DOMStoreTransaction}.
*
* Abstract base for composite transaction, which provides access only to common functionality as retrieval of
* subtransaction, close method and retrieval of identifier.
*
* @param Subtransaction type
*/
abstract class AbstractDOMForwardedTransaction
implements DOMDataTreeTransaction {
private static final VarHandle BACKING_TX;
static {
try {
BACKING_TX = MethodHandles.lookup().findVarHandle(AbstractDOMForwardedTransaction.class,
"backingTx", Entry.class);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new ExceptionInInitializerError(e);
}
}
private final @NonNull Object identifier;
private final Function backingTxFactory;
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD",
justification = "https://github.com/spotbugs/spotbugs/issues/2749")
private volatile Entry backingTx;
/**
* Creates new composite Transactions.
*
* @param identifier
* Identifier of transaction.
* @param backingTxFactory
* Function which supplies transaction depending on store type
*/
protected AbstractDOMForwardedTransaction(final Object identifier,
final Function backingTxFactory) {
this.identifier = requireNonNull(identifier, "Identifier should not be null");
this.backingTxFactory = requireNonNull(backingTxFactory, "Backing transaction factory should not be null");
}
/**
* Returns subtransaction associated with supplied datastore type.
*
* The method allows usage of single datastore type per transaction instance; eligible datastore type is defined
* by first method access.
*
* @param datastoreType is used to identify subtransaction object
* @return the subtransaction object
* @throws NullPointerException if datastoreType is {@code null}
* @throws IllegalArgumentException if datastoreType is not supported
* @throws TransactionDatastoreMismatchException if datastoreType mismatches the one used at first access
*/
protected final @NonNull T getSubtransaction(final LogicalDatastoreType datastoreType) {
final var ds = requireNonNull(datastoreType, "datastoreType must not be null.");
var entry = backingTx;
if (entry == null) {
final var tx = backingTxFactory.apply(datastoreType);
final var newEntry = Map.entry(ds, tx);
final var witness = (Entry) BACKING_TX.compareAndExchange(this, null, newEntry);
if (witness != null) {
tx.close();
entry = witness;
} else {
entry = newEntry;
}
}
final var encountered = entry.getKey();
if (encountered != ds) {
throw new TransactionDatastoreMismatchException(encountered, ds);
}
return entry.getValue();
}
/**
* Returns immutable Iterable of all subtransactions.
*/
protected @Nullable T getSubtransaction() {
final Entry entry;
return (entry = backingTx) == null ? null : entry.getValue();
}
@Override
public Object getIdentifier() {
return identifier;
}
@SuppressWarnings("checkstyle:IllegalCatch")
protected void closeSubtransactions() {
/*
* We share one exception for all failures, which are added
* as supressedExceptions to it.
*/
final var subtransaction = getSubtransaction();
if (subtransaction != null) {
try {
subtransaction.close();
} catch (Exception e) {
// If we did not allocate failure we allocate it
throw new IllegalStateException("Uncaught exception occurred during closing transaction", e);
}
}
}
}