import com.google.common.base.CharMatcher;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
-import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import java.math.BigInteger;
import java.net.URI;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
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.api.schema.tree.ModifiedNodeDoesNotExistException;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
return operationsFromModulesToNormalizedContext(modules, mountPoint);
}
+ /**
+ * Special case only for GET restconf/operations use (since moment of pre-Beryllium
+ * Yang parser and Yang model API removal). The method is creating fake
+ * schema context with fake module and fake data by use own implementations
+ * of schema nodes and module.
+ *
+ * @param modules
+ * - set of modules for get RPCs from every module
+ * @param mountPoint
+ * - mount point, if in use otherwise null
+ * @return {@link NormalizedNodeContext}
+ */
private NormalizedNodeContext operationsFromModulesToNormalizedContext(final Set<Module> modules,
final DOMMountPoint mountPoint) {
- throw new UnsupportedOperationException();
+
+ final ContainerSchemaNodeImpl fakeCont = new ContainerSchemaNodeImpl();
+ final List<LeafNode<Object>> listRpcNodes = new ArrayList<>();
+ for (final Module m : modules) {
+ for (final RpcDefinition rpc : m.getRpcs()) {
+
+ final LeafSchemaNode fakeLeaf = new LeafSchemaNodeImpl(fakeCont.getPath(),
+ QName.create(ModuleImpl.moduleQName, m.getName() + ":" + rpc.getQName().getLocalName()));
+ fakeCont.addNodeChild(fakeLeaf);
+ listRpcNodes.add(Builders.leafBuilder(fakeLeaf).build());
+ }
+ }
+ final ContainerSchemaNode fakeContSchNode = fakeCont;
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
+ .containerBuilder(fakeContSchNode);
+
+ for (final LeafNode<Object> rpcNode : listRpcNodes) {
+ containerBuilder.withChild(rpcNode);
+ }
+
+ final Module fakeModule = new ModuleImpl(fakeContSchNode);
+
+ final Set<Module> fakeModules = new HashSet<>();
+ fakeModules.add(fakeModule);
+ final SchemaContext fakeSchemaCtx = EffectiveSchemaContext.resolveSchemaContext(fakeModules);
+ final InstanceIdentifierContext<ContainerSchemaNode> instanceIdentifierContext = new InstanceIdentifierContext<>(
+ null, fakeContSchNode, mountPoint, fakeSchemaCtx);
+ return new NormalizedNodeContext(instanceIdentifierContext, containerBuilder.build());
}
private Module getRestconfModule() {
// did not expect any input
throw new RestconfDocumentedException("No input expected.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
- // else
- // {
- // TODO: Validate "mandatory" and "config" values here??? Or should those be
- // those be
- // validate in a more central location inside MD-SAL core.
- // }
}
private CheckedFuture<DOMRpcResult, DOMRpcException> invokeSalRemoteRpcSubscribeRPC(final NormalizedNodeContext payload) {
* failures back to the client and forcing them to handle it via retry (and having to
* document the behavior).
*/
- int tries = 2;
+ PutResult result = null;
+ final TryOfPutData tryPutData = new TryOfPutData();
while(true) {
- try {
- if (mountPoint != null) {
- this.broker.commitConfigurationDataPut(mountPoint, normalizedII, payload.getData()).checkedGet();
- } else {
- this.broker.commitConfigurationDataPut(this.controllerContext.getGlobalSchema(), normalizedII, payload.getData()).checkedGet();
+ if (mountPoint != null) {
+
+ result = this.broker.commitMountPointDataPut(mountPoint, normalizedII, payload.getData());
+ } else {
+ result = this.broker.commitConfigurationDataPut(this.controllerContext.getGlobalSchema(), normalizedII,
+ payload.getData());
+ }
+ final CountDownLatch waiter = new CountDownLatch(1);
+ Futures.addCallback(result.getFutureOfPutData(), new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(final Void result) {
+ handlingLoggerPut(null, tryPutData, identifier);
+ waiter.countDown();
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ waiter.countDown();
+ handlingLoggerPut(t, tryPutData, identifier);
}
+ });
+ try {
+ waiter.await();
+ } catch (final InterruptedException e) {
+ final String msg = "Problem while waiting for response";
+ LOG.warn(msg);
+ throw new RestconfDocumentedException(msg, e);
+ }
+
+ if(tryPutData.isDone()){
break;
- } catch (final TransactionCommitFailedException e) {
- if(e instanceof OptimisticLockFailedException) {
- if(--tries <= 0) {
- LOG.debug("Got OptimisticLockFailedException on last try - failing " + identifier);
- throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
- }
+ } else {
+ throw new RestconfDocumentedException("Problem while PUT operations");
+ }
+ }
- LOG.debug("Got OptimisticLockFailedException - trying again " + identifier);
- } else {
- LOG.debug("Update ConfigDataStore fail " + identifier, e);
- throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
+ return Response.status(result.getStatus()).build();
+ }
+
+ protected void handlingLoggerPut(final Throwable t, final TryOfPutData tryPutData, final String identifier) {
+ if (t != null) {
+ if (t instanceof OptimisticLockFailedException) {
+ if (tryPutData.countGet() <= 0) {
+ LOG.debug("Got OptimisticLockFailedException on last try - failing " + identifier);
+ throw new RestconfDocumentedException(t.getMessage(), t);
}
- } catch (final Exception e) {
- final String errMsg = "Error updating data ";
- LOG.debug(errMsg + identifier, e);
- throw new RestconfDocumentedException(errMsg, e);
+ LOG.debug("Got OptimisticLockFailedException - trying again " + identifier);
+ tryPutData.countDown();
+ } else {
+ LOG.debug("Update ConfigDataStore fail " + identifier, t);
+ throw new RestconfDocumentedException(t.getMessage(), t);
}
+ } else {
+ LOG.trace("PUT Successful " + identifier);
+ tryPutData.done();
}
-
- return Response.status(Status.OK).build();
}
private static void validateTopLevelNodeName(final NormalizedNodeContext node,
final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
- try {
- if (mountPoint != null) {
- this.broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData()).checkedGet();
- } else {
- this.broker.commitConfigurationDataPost(this.controllerContext.getGlobalSchema(), normalizedII, payload.getData()).checkedGet();
+
+ CheckedFuture<Void, TransactionCommitFailedException> future;
+ if (mountPoint != null) {
+ future = this.broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData());
+ } else {
+ future = this.broker.commitConfigurationDataPost(this.controllerContext.getGlobalSchema(), normalizedII,
+ payload.getData());
+ }
+
+ final CountDownLatch waiter = new CountDownLatch(1);
+ Futures.addCallback(future, new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(final Void result) {
+ handlerLoggerPost(null, uriInfo);
+ waiter.countDown();
}
- } catch(final RestconfDocumentedException e) {
- throw e;
- } catch (final Exception e) {
- final String errMsg = "Error creating data ";
- LOG.info(errMsg + (uriInfo != null ? uriInfo.getPath() : ""), e);
- throw new RestconfDocumentedException(errMsg, e);
+
+ @Override
+ public void onFailure(final Throwable t) {
+ waiter.countDown();
+ handlerLoggerPost(t, uriInfo);
+ }
+ });
+
+ try {
+ waiter.await();
+ } catch (final InterruptedException e) {
+ final String msg = "Problem while waiting for response";
+ LOG.warn(msg);
+ throw new RestconfDocumentedException(msg, e);
}
final ResponseBuilder responseBuilder = Response.status(Status.NO_CONTENT);
return responseBuilder.build();
}
+ protected void handlerLoggerPost(final Throwable t, final UriInfo uriInfo) {
+ if (t != null) {
+ final String errMsg = "Error creating data ";
+ LOG.warn(errMsg + (uriInfo != null ? uriInfo.getPath() : ""), t);
+ throw new RestconfDocumentedException(errMsg, t);
+ } else {
+ LOG.trace("Successfuly create data.");
+ }
+ }
+
private URI resolveLocation(final UriInfo uriInfo, final String uriBehindBase, final DOMMountPoint mountPoint, final YangInstanceIdentifier normalizedII) {
if(uriInfo == null) {
// This is null if invoked internally
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
- try {
- if (mountPoint != null) {
- this.broker.commitConfigurationDataDelete(mountPoint, normalizedII);
- } else {
- this.broker.commitConfigurationDataDelete(normalizedII).get();
+ final CheckedFuture<Void, TransactionCommitFailedException> future;
+ if (mountPoint != null) {
+ future = this.broker.commitConfigurationDataDelete(mountPoint, normalizedII);
+ } else {
+ future = this.broker.commitConfigurationDataDelete(normalizedII);
+ }
+
+ final CountDownLatch waiter = new CountDownLatch(1);
+ Futures.addCallback(future, new FutureCallback<Void>() {
+
+ @Override
+ public void onSuccess(final Void result) {
+ handlerLoggerDelete(null);
+ waiter.countDown();
}
- } catch (final Exception e) {
- final Optional<Throwable> searchedException = Iterables.tryFind(Throwables.getCausalChain(e),
- Predicates.instanceOf(ModifiedNodeDoesNotExistException.class));
- if (searchedException.isPresent()) {
- throw new RestconfDocumentedException("Data specified for deleting doesn't exist.", ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
+
+ @Override
+ public void onFailure(final Throwable t) {
+ waiter.countDown();
+ handlerLoggerDelete(t);
}
- final String errMsg = "Error while deleting data";
- LOG.info(errMsg, e);
- throw new RestconfDocumentedException(errMsg, e);
+
+ });
+
+ try {
+ waiter.await();
+ } catch (final InterruptedException e) {
+ final String msg = "Problem while waiting for response";
+ LOG.warn(msg);
+ throw new RestconfDocumentedException(msg, e);
}
+
return Response.status(Status.OK).build();
}
+ protected void handlerLoggerDelete(final Throwable t) {
+ if (t != null) {
+ final String errMsg = "Error while deleting data";
+ LOG.info(errMsg, t);
+ throw new RestconfDocumentedException(errMsg, t);
+ } else {
+ LOG.trace("Successfuly delete data.");
+ }
+ }
+
/**
* Subscribes to some path in schema context (stream) to listen on changes on this stream.
*
return result;
}
- public BigInteger getOperationalReceived() {
- // TODO Auto-generated method stub
- return null;
- }
-
private MapNode makeModuleMapNode(final Set<Module> modules) {
Preconditions.checkNotNull(modules);
final Module restconfModule = getRestconfModule();
return Futures.immediateCheckedFuture(defaultDOMRpcResult);
}
+
+ private class TryOfPutData {
+ int tries = 2;
+ boolean done = false;
+
+ void countDown() {
+ this.tries--;
+ }
+
+ void done() {
+ this.done = true;
+ }
+
+ boolean isDone() {
+ return this.done;
+ }
+ int countGet() {
+ return this.tries;
+ }
+ }
}