org.opendaylight.sxp.controller.core.DatastoreAccess.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.sxp.controller.core.DatastoreAccess.java

Source

/*
 * 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.sxp.controller.core;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.List;
import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.sxp.controller.listeners.TransactionChainListenerImpl;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class DatastoreAccess implements AutoCloseable {

    private static final Logger LOG = LoggerFactory.getLogger(DatastoreAccess.class.getName());
    private static final ReadFailedException ACCESS_CLOSED_ON_R = new ReadFailedException("Datastore was closed");
    private static final TransactionCommitFailedException ACCESS_CLOSED_ON_RW = new TransactionCommitFailedException(
            "Datastore was closed");

    private final TransactionChainListener chainListener;
    private BindingTransactionChain bindingTransactionChain;
    private final DataBroker dataBroker;
    private boolean closed = false;
    private final List<DatastoreAccess> childDatastoreAccesses = new ArrayList<>();

    /**
     * @param dataBroker DataBroker used for accessing data store
     * @return DataAccess used to access data store
     */
    public static DatastoreAccess getInstance(DataBroker dataBroker) {
        return new DatastoreAccess(Preconditions.checkNotNull(dataBroker));
    }

    /**
     * Creates Datastore access with Parent-child dependency,
     * when Parent is closed all its children are also closed.
     *
     * @param datastoreAccess DataAccess used to access data store
     * @return DataAccess used to access data store
     */
    public static DatastoreAccess getInstance(DatastoreAccess datastoreAccess) {
        DatastoreAccess child = new DatastoreAccess(Preconditions.checkNotNull(datastoreAccess).dataBroker);
        datastoreAccess.childDatastoreAccesses.add(child);
        return child;
    }

    /**
     * @param dataBroker DataBroker that will be used to access data store
     */
    private DatastoreAccess(DataBroker dataBroker) {
        this.chainListener = new TransactionChainListenerImpl(this);
        this.dataBroker = Preconditions.checkNotNull(dataBroker);
        bindingTransactionChain = this.dataBroker.createTransactionChain(chainListener);
    }

    /**
     * @param path                 Idetifier path to be checked
     * @param logicalDatastoreType DataStore type to be checked
     * @param <T>                  Any type extending DataObject
     */
    private <T extends DataObject> boolean checkParams(InstanceIdentifier<T> path,
            LogicalDatastoreType logicalDatastoreType) {
        if (closed) {
            return false;
        }
        Preconditions.checkNotNull(bindingTransactionChain);
        Preconditions.checkNotNull(logicalDatastoreType);
        Preconditions.checkNotNull(path);
        return true;
    }

    /**
     * @param path                 InstanceIdentifier path specifying data
     * @param logicalDatastoreType Type of datastore where operation will be held
     * @param <T>                  Any type extending DataObject
     * @return ListenableFuture callback of operation
     */
    public synchronized <T extends DataObject> ListenableFuture<Void> delete(InstanceIdentifier<T> path,
            LogicalDatastoreType logicalDatastoreType) {
        if (!checkParams(path, logicalDatastoreType)) {
            return Futures.immediateCancelledFuture();
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Delete {} {}", logicalDatastoreType, path.getTargetType());
        }
        synchronized (dataBroker) {
            WriteTransaction transaction = bindingTransactionChain.newWriteOnlyTransaction();
            transaction.delete(logicalDatastoreType, path);
            return transaction.submit();
        }
    }

    /**
     * @param path                 InstanceIdentifier path specifying data
     * @param data                 Data that will be used in operation
     * @param logicalDatastoreType Type of datastore where operation will be held
     * @param <T>                  Any type extending DataObject
     * @return CheckedFuture callback of operation
     */
    public synchronized <T extends DataObject> CheckedFuture<Void, TransactionCommitFailedException> merge(
            InstanceIdentifier<T> path, T data, LogicalDatastoreType logicalDatastoreType) {
        if (!checkParams(path, logicalDatastoreType)) {
            return Futures.makeChecked(Futures.immediateCancelledFuture(), input -> ACCESS_CLOSED_ON_RW);
        }
        Preconditions.checkNotNull(data);
        if (LOG.isDebugEnabled()) {
            LOG.debug("Merge {} {}", logicalDatastoreType, path.getTargetType());
        }
        WriteTransaction transaction = bindingTransactionChain.newWriteOnlyTransaction();
        transaction.merge(logicalDatastoreType, path, data);
        return transaction.submit();

    }

    /**
     * @param path                 InstanceIdentifier path specifying data
     * @param data                 Data that will be used in operation
     * @param logicalDatastoreType Type of datastore where operation will be held
     * @param <T>                  Any type extending DataObject
     * @return CheckedFuture callback of operation
     */
    public synchronized <T extends DataObject> CheckedFuture<Void, TransactionCommitFailedException> put(
            InstanceIdentifier<T> path, T data, LogicalDatastoreType logicalDatastoreType) {
        if (!checkParams(path, logicalDatastoreType)) {
            return Futures.makeChecked(Futures.immediateCancelledFuture(), input -> ACCESS_CLOSED_ON_RW);
        }
        Preconditions.checkNotNull(data);
        if (LOG.isDebugEnabled()) {
            LOG.debug("Put {} {}", logicalDatastoreType, path.getTargetType());
        }
        WriteTransaction transaction = bindingTransactionChain.newWriteOnlyTransaction();
        transaction.put(logicalDatastoreType, path, data);
        return transaction.submit();
    }

    /**
     * @param path                 InstanceIdentifier path specifying data
     * @param logicalDatastoreType Type of datastore where operation will be held
     * @param <T>                  Any type extending DataObject
     * @return CheckedFuture callback of operation
     */
    public synchronized <T extends DataObject> CheckedFuture<Optional<T>, ReadFailedException> read(
            InstanceIdentifier<T> path, LogicalDatastoreType logicalDatastoreType) {
        if (!checkParams(path, logicalDatastoreType)) {
            return Futures.makeChecked(Futures.immediateCancelledFuture(), input -> ACCESS_CLOSED_ON_R);
        }
        try (ReadOnlyTransaction transaction = bindingTransactionChain.newReadOnlyTransaction()) {
            return transaction.read(logicalDatastoreType, path);
        }
    }

    /**
     * @param path                 InstanceIdentifier path specifying data
     * @param data                 Data that will be used in operation
     * @param logicalDatastoreType Type of datastore where operation will be held
     * @param <T>                  Any type extending DataObject
     * @return If operation was successful
     */
    public synchronized <T extends DataObject> boolean mergeSynchronous(InstanceIdentifier<T> path, T data,
            LogicalDatastoreType logicalDatastoreType) {
        try {
            merge(path, data, logicalDatastoreType).checkedGet();
        } catch (TransactionCommitFailedException e) {
            return false;
        }
        return true;
    }

    /**
     * @param path                 InstanceIdentifier path specifying data
     * @param data                 Data that will be used in operation
     * @param logicalDatastoreType Type of datastore where operation will be held
     * @param <T>                  Any type extending DataObject
     * @return If operation was successful
     */
    public synchronized <T extends DataObject> boolean putSynchronous(InstanceIdentifier<T> path, T data,
            LogicalDatastoreType logicalDatastoreType) {
        try {
            put(path, data, logicalDatastoreType).checkedGet();
        } catch (TransactionCommitFailedException e) {
            return false;
        }
        return true;
    }

    /**
     * @param path                 InstanceIdentifier path specifying data
     * @param logicalDatastoreType Type of datastore where operation will be held
     * @param <T>                  Any type extending DataObject
     * @return Data read from datastore or null if operation was interrupted
     */
    public synchronized <T extends DataObject> T readSynchronous(InstanceIdentifier<T> path,
            LogicalDatastoreType logicalDatastoreType) {
        try {
            Optional<T> result = read(path, logicalDatastoreType).checkedGet();
            return result.isPresent() ? result.get() : null;
        } catch (ReadFailedException e) {
            return null;
        }
    }

    /**
     * @param identifier    InstanceIdentifier that will be checked
     * @param datastoreType Datastore type where datastore will be checked
     * @param <T>           Any type extending DataObject
     * @return If All parents of provided path exists
     */
    private <T extends DataObject> boolean checkParentExist(final InstanceIdentifier<T> identifier,
            final LogicalDatastoreType datastoreType) {
        final InstanceIdentifier.PathArgument[] arguments = Iterables.toArray(identifier.getPathArguments(),
                InstanceIdentifier.PathArgument.class);
        return arguments.length < 2
                || readSynchronous(identifier.firstIdentifierOf(arguments[arguments.length - 2].getType()),
                        datastoreType) != null;
    }

    /**
     * @param identifier    InstanceIdentifier path specifying data
     * @param data          Data that will be used in operation
     * @param datastoreType Type of datastore where operation will be held
     * @param mustContains  Specifying if object mus preexist or not
     * @param <T>           Any type extending DataObject
     * @return If operation was successful
     */
    public synchronized <T extends DataObject> boolean checkAndPut(InstanceIdentifier<T> identifier, T data,
            LogicalDatastoreType datastoreType, final boolean mustContains) {
        final boolean check = checkParentExist(identifier, datastoreType)
                && (mustContains ? readSynchronous(identifier, datastoreType) != null
                        : readSynchronous(identifier, datastoreType) == null);
        return check && !put(identifier, data, datastoreType).isCancelled();
    }

    /**
     * @param identifier    InstanceIdentifier path specifying data
     * @param data          Data that will be used in operation
     * @param datastoreType Type of datastore where operation will be held
     * @param mustContains  Specifying if object mus preexist or not
     * @param <T>           Any type extending DataObject
     * @return If operation was successful
     */
    public synchronized <T extends DataObject> boolean checkAndMerge(InstanceIdentifier<T> identifier, T data,
            LogicalDatastoreType datastoreType, final boolean mustContains) {
        final boolean check = checkParentExist(identifier, datastoreType)
                && (mustContains ? readSynchronous(identifier, datastoreType) != null
                        : readSynchronous(identifier, datastoreType) == null);
        if (check) {
            return !merge(identifier, data, datastoreType).isCancelled();
        }
        return false;
    }

    /**
     * @param identifier    InstanceIdentifier path specifying data
     * @param datastoreType Type of datastore where operation will be held
     * @param <T>           Any type extending DataObject
     * @return If operation was successful
     */
    public synchronized <T extends DataObject> boolean checkAndDelete(InstanceIdentifier<T> identifier,
            LogicalDatastoreType datastoreType) {
        if (readSynchronous(identifier, datastoreType) != null) {
            return !delete(identifier, datastoreType).isCancelled();
        }
        return false;
    }

    /**
     * Recreate transaction chain if error occurred and decrement allowed error rate counter
     */
    public synchronized void reinitializeChain() {
        if (!closed) {
            bindingTransactionChain.close();
            bindingTransactionChain = dataBroker.createTransactionChain(chainListener);
        }
    }

    @Override
    public synchronized void close() {
        if (!closed) {
            closed = true;
            bindingTransactionChain.close();
            childDatastoreAccesses.forEach(DatastoreAccess::close);
        }
    }
}