*/
package org.opendaylight.controller.sal.restconf.impl;
-import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
-import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
-
import com.google.common.base.Optional;
import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import javax.ws.rs.core.Response.Status;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
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.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.ws.rs.core.Response.Status;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
+
public class BrokerFacade {
private final static Logger LOG = LoggerFactory.getLogger(BrokerFacade.class);
public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPut(
final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
checkPreconditions();
- return putDataViaTransaction(domDataBroker.newWriteOnlyTransaction(), CONFIGURATION, path, payload);
+ DataNormalizationOperation<?> rootOp = ControllerContext.getInstance().getRootOperation();
+ return putDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, rootOp);
}
public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPut(
final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
if (domDataBrokerService.isPresent()) {
- return putDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path,
- payload);
+ DataNormalizationOperation<?> rootOp = new DataNormalizer(mountPoint.getSchemaContext()).getRootOperation();
+ return putDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
+ payload, rootOp);
}
throw new RestconfDocumentedException("DOM data broker service isn't available for mount point.");
}
public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
checkPreconditions();
- return postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload);
+ DataNormalizationOperation<?> rootOp = ControllerContext.getInstance().getRootOperation();
+ return postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, rootOp);
}
public CheckedFuture<Void, TransactionCommitFailedException> commitConfigurationDataPost(
final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
if (domDataBrokerService.isPresent()) {
+ DataNormalizationOperation<?> rootOp = new DataNormalizer(mountPoint.getSchemaContext()).getRootOperation();
return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path,
- payload);
+ payload, rootOp);
}
throw new RestconfDocumentedException("DOM data broker service isn't available for mount point.");
}
private NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction transaction,
LogicalDatastoreType datastore, YangInstanceIdentifier path) {
LOG.trace("Read " + datastore.name() + " via Restconf: {}", path);
- final ListenableFuture<Optional<NormalizedNode<?, ?>>> listenableFuture = transaction.read(datastore, path);
- if (listenableFuture != null) {
- Optional<NormalizedNode<?, ?>> optional;
- try {
- LOG.debug("Reading result data from transaction.");
- optional = listenableFuture.get();
- } catch (InterruptedException | ExecutionException e) {
- throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause());
+ final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture =
+ transaction.read(datastore, path);
- }
- if (optional != null) {
- if (optional.isPresent()) {
- return optional.get();
- }
- }
+ try {
+ Optional<NormalizedNode<?, ?>> optional = listenableFuture.checkedGet();
+ return optional.isPresent() ? optional.get() : null;
+ } catch(ReadFailedException e) {
+ throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
}
- return null;
}
private CheckedFuture<Void, TransactionCommitFailedException> postDataViaTransaction(
final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore,
- final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
- ListenableFuture<Optional<NormalizedNode<?, ?>>> futureDatastoreData = rWTransaction.read(datastore, path);
+ final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, DataNormalizationOperation<?> root) {
+ CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> futureDatastoreData =
+ rWTransaction.read(datastore, path);
try {
- final Optional<NormalizedNode<?, ?>> optionalDatastoreData = futureDatastoreData.get();
+ final Optional<NormalizedNode<?, ?>> optionalDatastoreData = futureDatastoreData.checkedGet();
if (optionalDatastoreData.isPresent() && payload.equals(optionalDatastoreData.get())) {
- String errMsg = "Post Configuration via Restconf was not executed because data already exists";
- LOG.trace(errMsg + ":{}", path);
+ LOG.trace("Post Configuration via Restconf was not executed because data already exists :{}", path);
throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL,
ErrorTag.DATA_EXISTS);
}
- } catch (InterruptedException | ExecutionException e) {
- LOG.trace("It wasn't possible to get data loaded from datastore at path " + path);
+ } catch(ReadFailedException e) {
+ LOG.warn("Error reading from datastore with path: " + path, e);
}
+
+ ensureParentsByMerge(datastore, path, rWTransaction, root);
rWTransaction.merge(datastore, path, payload);
LOG.trace("Post " + datastore.name() + " via Restconf: {}", path);
return rWTransaction.submit();
}
private CheckedFuture<Void, TransactionCommitFailedException> putDataViaTransaction(
- final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
- final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload) {
+ final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore,
+ final YangInstanceIdentifier path, final NormalizedNode<?, ?> payload, DataNormalizationOperation<?> root) {
LOG.trace("Put " + datastore.name() + " via Restconf: {}", path);
+ ensureParentsByMerge(datastore, path, writeTransaction, root);
writeTransaction.put(datastore, path, payload);
return writeTransaction.submit();
}
public void setDomDataBroker(DOMDataBroker domDataBroker) {
this.domDataBroker = domDataBroker;
}
+
+ private final void ensureParentsByMerge(final LogicalDatastoreType store,
+ final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx,
+ final DataNormalizationOperation<?> root) {
+ List<PathArgument> currentArguments = new ArrayList<>();
+ Iterator<PathArgument> iterator = normalizedPath.getPathArguments().iterator();
+ DataNormalizationOperation<?> currentOp = root;
+ while (iterator.hasNext()) {
+ PathArgument currentArg = iterator.next();
+ try {
+ currentOp = currentOp.getChild(currentArg);
+ } catch (DataNormalizationException e) {
+ throw new RestconfDocumentedException(
+ String.format("Error normalizing data for path %s", normalizedPath), e);
+ }
+ currentArguments.add(currentArg);
+ YangInstanceIdentifier currentPath = YangInstanceIdentifier.create(currentArguments);
+
+ try {
+
+ boolean exists = rwTx.exists(store, currentPath).checkedGet();
+ if (!exists && iterator.hasNext()) {
+ rwTx.merge(store, currentPath, currentOp.createDefault(currentArg));
+ }
+ } catch (ReadFailedException e) {
+ LOG.error("Failed to read pre-existing data from store {} path {}", store, currentPath, e);
+ throw new RestconfDocumentedException("Failed to read pre-existing data", e);
+ }
+ }
+ }
}