X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-rest-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Frestconf%2Fimpl%2FBrokerFacade.java;h=b8d9561a26069aab4fbfc94bd134f729b4dd4a23;hp=9c2c932d510cc4d8f3ed4ec9d1dd97a5a43b7499;hb=9ba2b4eca79bcc0e78099b133296801c8d45a6c4;hpb=88216bef92ecb0d4df4345ed823faf1777966256 diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java index 9c2c932d51..b8d9561a26 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/BrokerFacade.java @@ -10,21 +10,17 @@ 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.base.Preconditions; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListenableFuture; import java.util.ArrayList; import java.util.Iterator; import java.util.List; 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; @@ -39,12 +35,13 @@ import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.common.QName; -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.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,7 +86,9 @@ public class BrokerFacade { if (domDataBrokerService.isPresent()) { return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), CONFIGURATION, path); } - throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + final String errMsg = "DOM data broker service isn't available for mount point " + path; + LOG.warn(errMsg); + throw new RestconfDocumentedException(errMsg); } // READ operational @@ -103,45 +102,47 @@ public class BrokerFacade { if (domDataBrokerService.isPresent()) { return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), OPERATIONAL, path); } - throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + final String errMsg = "DOM data broker service isn't available for mount point " + path; + LOG.warn(errMsg); + throw new RestconfDocumentedException(errMsg); } // PUT configuration public CheckedFuture commitConfigurationDataPut( - final YangInstanceIdentifier path, final NormalizedNode payload) { + final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode payload) { checkPreconditions(); - final DataNormalizationOperation rootOp = ControllerContext.getInstance().getRootOperation(); - return putDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, rootOp); + return putDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, globalSchema); } public CheckedFuture commitConfigurationDataPut( final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode payload) { final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); if (domDataBrokerService.isPresent()) { - final DataNormalizationOperation rootOp = new DataNormalizer(mountPoint.getSchemaContext()).getRootOperation(); return putDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path, - payload, rootOp); + payload, mountPoint.getSchemaContext()); } - throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + final String errMsg = "DOM data broker service isn't available for mount point " + path; + LOG.warn(errMsg); + throw new RestconfDocumentedException(errMsg); } // POST configuration public CheckedFuture commitConfigurationDataPost( - final YangInstanceIdentifier path, final NormalizedNode payload) { + final SchemaContext globalSchema, final YangInstanceIdentifier path, final NormalizedNode payload) { checkPreconditions(); - final DataNormalizationOperation rootOp = ControllerContext.getInstance().getRootOperation(); - return postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, rootOp); + return postDataViaTransaction(domDataBroker.newReadWriteTransaction(), CONFIGURATION, path, payload, globalSchema); } public CheckedFuture commitConfigurationDataPost( final DOMMountPoint mountPoint, final YangInstanceIdentifier path, final NormalizedNode payload) { final Optional domDataBrokerService = mountPoint.getService(DOMDataBroker.class); if (domDataBrokerService.isPresent()) { - final DataNormalizationOperation rootOp = new DataNormalizer(mountPoint.getSchemaContext()).getRootOperation(); return postDataViaTransaction(domDataBrokerService.get().newReadWriteTransaction(), CONFIGURATION, path, - payload, rootOp); + payload, mountPoint.getSchemaContext()); } - throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + final String errMsg = "DOM data broker service isn't available for mount point " + path; + LOG.warn(errMsg); + throw new RestconfDocumentedException(errMsg); } // DELETE configuration @@ -157,7 +158,9 @@ public class BrokerFacade { if (domDataBrokerService.isPresent()) { return deleteDataViaTransaction(domDataBrokerService.get().newWriteOnlyTransaction(), CONFIGURATION, path); } - throw new RestconfDocumentedException("DOM data broker service isn't available for mount point."); + final String errMsg = "DOM data broker service isn't available for mount point " + path; + LOG.warn(errMsg); + throw new RestconfDocumentedException(errMsg); } // RPC @@ -169,16 +172,6 @@ public class BrokerFacade { return rpcService.invokeRpc(type, input); } - /** - * @deprecated methode has to be removed in Lithium release - */ - @Deprecated - public Future> invokeRpc(final QName type, final CompositeNode payload) { - checkPreconditions(); - - return context.rpc(type, payload); - } - public void registerToListenDataChanges(final LogicalDatastoreType datastore, final DataChangeScope scope, final ListenerAdapter listener) { checkPreconditions(); @@ -204,6 +197,7 @@ public class BrokerFacade { LOG.debug("Reading result data from transaction."); optional = listenableFuture.get(); } catch (InterruptedException | ExecutionException e) { + LOG.warn("Exception by reading " + datastore.name() + " via Restconf: {}", path, e); throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause()); } @@ -218,11 +212,30 @@ public class BrokerFacade { private CheckedFuture postDataViaTransaction( final DOMDataReadWriteTransaction rWTransaction, final LogicalDatastoreType datastore, - final YangInstanceIdentifier path, final NormalizedNode payload, final DataNormalizationOperation root) { - final ListenableFuture>> futureDatastoreData = rWTransaction.read(datastore, path); + final YangInstanceIdentifier path, final NormalizedNode payload, final SchemaContext schemaContext) { + // FIXME: This is doing correct post for container and list children + // not sure if this will work for choice case + if(payload instanceof MapNode) { + final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path); + rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree); + ensureParentsByMerge(datastore, path, rWTransaction, schemaContext); + for(final MapEntryNode child : ((MapNode) payload).getValue()) { + final YangInstanceIdentifier childPath = path.node(child.getIdentifier()); + checkItemDoesNotExists(rWTransaction, datastore, childPath); + rWTransaction.put(datastore, childPath, child); + } + } else { + checkItemDoesNotExists(rWTransaction,datastore, path); + ensureParentsByMerge(datastore, path, rWTransaction, schemaContext); + rWTransaction.put(datastore, path, payload); + } + return rWTransaction.submit(); + } + + private void checkItemDoesNotExists(final DOMDataReadWriteTransaction rWTransaction,final LogicalDatastoreType store, final YangInstanceIdentifier path) { + final ListenableFuture futureDatastoreData = rWTransaction.exists(store, path); try { - final Optional> optionalDatastoreData = futureDatastoreData.get(); - if (optionalDatastoreData.isPresent() && payload.equals(optionalDatastoreData.get())) { + if (futureDatastoreData.get()) { final String errMsg = "Post Configuration via Restconf was not executed because data already exists"; LOG.trace(errMsg + ":{}", path); rWTransaction.cancel(); @@ -230,20 +243,16 @@ public class BrokerFacade { ErrorTag.DATA_EXISTS); } } catch (InterruptedException | ExecutionException e) { - LOG.trace("It wasn't possible to get data loaded from datastore at path " + path); + LOG.warn("It wasn't possible to get data loaded from datastore at 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 putDataViaTransaction( final DOMDataReadWriteTransaction writeTransaction, final LogicalDatastoreType datastore, - final YangInstanceIdentifier path, final NormalizedNode payload, final DataNormalizationOperation root) { + final YangInstanceIdentifier path, final NormalizedNode payload, final SchemaContext schemaContext) { LOG.trace("Put " + datastore.name() + " via Restconf: {}", path); - ensureParentsByMerge(datastore, path, writeTransaction, root); + ensureParentsByMerge(datastore, path, writeTransaction, schemaContext); writeTransaction.put(datastore, path, payload); return writeTransaction.submit(); } @@ -260,39 +269,34 @@ public class BrokerFacade { this.domDataBroker = domDataBroker; } - private final void ensureParentsByMerge(final LogicalDatastoreType store, - final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx, - final DataNormalizationOperation root) { - final List currentArguments = new ArrayList<>(); - final Iterator iterator = normalizedPath.getPathArguments().iterator(); - DataNormalizationOperation currentOp = root; - while (iterator.hasNext()) { - final PathArgument currentArg = iterator.next(); - try { - currentOp = currentOp.getChild(currentArg); - } catch (final DataNormalizationException e) { - rwTx.cancel(); - throw new IllegalArgumentException( - String.format("Invalid child encountered in path %s", normalizedPath), e); - } - currentArguments.add(currentArg); - final YangInstanceIdentifier currentPath = YangInstanceIdentifier.create(currentArguments); + private void ensureParentsByMerge(final LogicalDatastoreType store, + final YangInstanceIdentifier normalizedPath, final DOMDataReadWriteTransaction rwTx, final SchemaContext schemaContext) { + final List normalizedPathWithoutChildArgs = new ArrayList<>(); + YangInstanceIdentifier rootNormalizedPath = null; - final Boolean exists; + final Iterator it = normalizedPath.getPathArguments().iterator(); - try { - - final CheckedFuture future = rwTx.exists(store, currentPath); - exists = future.checkedGet(); - } catch (final ReadFailedException e) { - LOG.error("Failed to read pre-existing data from store {} path {}", store, currentPath, e); - rwTx.cancel(); - throw new IllegalStateException("Failed to read pre-existing data", e); + while(it.hasNext()) { + final PathArgument pathArgument = it.next(); + if(rootNormalizedPath == null) { + rootNormalizedPath = YangInstanceIdentifier.create(pathArgument); } - if (!exists && iterator.hasNext()) { - rwTx.merge(store, currentPath, currentOp.createDefault(currentArg)); + // Skip last element, its not a parent + if(it.hasNext()) { + normalizedPathWithoutChildArgs.add(pathArgument); } } + + // No parent structure involved, no need to ensure parents + if(normalizedPathWithoutChildArgs.isEmpty()) { + return; + } + + Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received"); + + final NormalizedNode parentStructure = + ImmutableNodes.fromInstanceId(schemaContext, YangInstanceIdentifier.create(normalizedPathWithoutChildArgs)); + rwTx.merge(store, rootNormalizedPath, parentStructure); } }