/**
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- * Copyright (c) 2014 Brocade Communication Systems, Inc.
+ * Copyright (c) 2014, 2015 Brocade Communication Systems, Inc., 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.controller.sal.restconf.impl;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
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.Futures;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.controller.md.sal.rest.common.RestconfValidationUtils;
import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.api.RestconfService;
import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag;
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.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
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.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+import org.opendaylight.yangtools.yang.model.util.EmptyType;
import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RestconfImpl implements RestconfService {
- private enum UriParameters {
- PRETTY_PRINT("prettyPrint"),
- DEPTH("depth");
-
- private String uriParameterName;
-
- UriParameters(final String uriParameterName) {
- this.uriParameterName = uriParameterName;
- }
-
- @Override
- public String toString() {
- return uriParameterName;
- }
- }
-
- private static class TypeDef {
- public final TypeDefinition<? extends Object> typedef;
- public final QName qName;
-
- TypeDef(final TypeDefinition<? extends Object> typedef, final QName qName) {
- this.typedef = typedef;
- this.qName = qName;
- }
- }
-
- private final static RestconfImpl INSTANCE = new RestconfImpl();
+ private static final RestconfImpl INSTANCE = new RestconfImpl();
private static final int NOTIFICATION_PORT = 8181;
private static final int CHAR_NOT_FOUND = -1;
- private final static String MOUNT_POINT_MODULE_NAME = "ietf-netconf";
+ private static final String MOUNT_POINT_MODULE_NAME = "ietf-netconf";
- private final static SimpleDateFormat REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+ private static final SimpleDateFormat REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
- private final static String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
+ private static final String SAL_REMOTE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote";
- private final static String SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription";
+ private static final String SAL_REMOTE_RPC_SUBSRCIBE = "create-data-change-event-subscription";
private BrokerFacade broker;
SAL_REMOTE_AUG_IDENTIFIER = new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(QName.create(SAL_REMOTE_AUGMENT, "scope"),
QName.create(SAL_REMOTE_AUGMENT, "datastore")));
} catch (final ParseException e) {
- throw new RestconfDocumentedException(
- "It wasn't possible to convert revision date of sal-remote-augment to date", ErrorType.APPLICATION,
- ErrorTag.OPERATION_FAILED);
+ final String errMsg = "It wasn't possible to convert revision date of sal-remote-augment to date";
+ LOG.debug(errMsg);
+ throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
} catch (final URISyntaxException e) {
- throw new RestconfDocumentedException(
- "It wasn't possible to create instance of URI class with "+NETCONF_BASE+" URI", ErrorType.APPLICATION,
- ErrorTag.OPERATION_FAILED);
+ final String errMsg = "It wasn't possible to create instance of URI class with "+NETCONF_BASE+" URI";
+ throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
}
}
Builders.containerBuilder((ContainerSchemaNode) modulesSchemaNode);
moduleContainerBuilder.withChild(allModuleMap);
- return new NormalizedNodeContext(new InstanceIdentifierContext(null, modulesSchemaNode,
- null, schemaContext), moduleContainerBuilder.build());
+ return new NormalizedNodeContext(new InstanceIdentifierContext<>(null, modulesSchemaNode,
+ null, schemaContext), moduleContainerBuilder.build(),
+ QueryParametersParser.parseWriterParameters(uriInfo));
}
/**
if ( ! identifier.contains(ControllerContext.MOUNT)) {
final String errMsg = "URI has bad format. If modules behind mount point should be showed,"
+ " URI has to end with " + ControllerContext.MOUNT;
+ LOG.debug(errMsg + " for " + identifier);
throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
- final InstanceIdentifierContext mountPointIdentifier = controllerContext.toMountPointIdentifier(identifier);
+ final InstanceIdentifierContext<?> mountPointIdentifier = controllerContext.toMountPointIdentifier(identifier);
final DOMMountPoint mountPoint = mountPointIdentifier.getMountPoint();
final Set<Module> modules = controllerContext.getAllModules(mountPoint);
- final SchemaContext schemaContext = mountPoint.getSchemaContext();
final MapNode mountPointModulesMap = makeModuleMapNode(modules);
final Module restconfModule = getRestconfModule();
Builders.containerBuilder((ContainerSchemaNode) modulesSchemaNode);
moduleContainerBuilder.withChild(mountPointModulesMap);
- return new NormalizedNodeContext(new InstanceIdentifierContext(null, modulesSchemaNode,
- mountPoint, controllerContext.getGlobalSchema()), moduleContainerBuilder.build());
+ return new NormalizedNodeContext(new InstanceIdentifierContext<>(null, modulesSchemaNode,
+ mountPoint, controllerContext.getGlobalSchema()), moduleContainerBuilder.build(),
+ QueryParametersParser.parseWriterParameters(uriInfo));
}
@Override
DOMMountPoint mountPoint = null;
final SchemaContext schemaContext;
if (identifier.contains(ControllerContext.MOUNT)) {
- final InstanceIdentifierContext mountPointIdentifier = controllerContext.toMountPointIdentifier(identifier);
+ final InstanceIdentifierContext<?> mountPointIdentifier = controllerContext.toMountPointIdentifier(identifier);
mountPoint = mountPointIdentifier.getMountPoint();
module = controllerContext.findModuleByNameAndRevision(mountPoint, moduleNameAndRevision);
schemaContext = mountPoint.getSchemaContext();
if (module == null) {
final String errMsg = "Module with name '" + moduleNameAndRevision.getLocalName()
+ "' and revision '" + moduleNameAndRevision.getRevision() + "' was not found.";
+ LOG.debug(errMsg);
throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
Preconditions.checkState(moduleSchemaNode instanceof ListSchemaNode);
- return new NormalizedNodeContext(new InstanceIdentifierContext(null, moduleSchemaNode, mountPoint,
- schemaContext), moduleMap);
+ return new NormalizedNodeContext(new InstanceIdentifierContext<>(null, moduleSchemaNode, mountPoint,
+ schemaContext), moduleMap, QueryParametersParser.parseWriterParameters(uriInfo));
}
@Override
streamsContainerBuilder.withChild(listStreamsBuilder.build());
- return new NormalizedNodeContext(new InstanceIdentifierContext(null, streamsContainerSchemaNode, null,
- schemaContext), streamsContainerBuilder.build());
+ return new NormalizedNodeContext(new InstanceIdentifierContext<>(null, streamsContainerSchemaNode, null,
+ schemaContext), streamsContainerBuilder.build(), QueryParametersParser.parseWriterParameters(uriInfo));
}
@Override
Set<Module> modules = null;
DOMMountPoint mountPoint = null;
if (identifier.contains(ControllerContext.MOUNT)) {
- final InstanceIdentifierContext mountPointIdentifier = controllerContext.toMountPointIdentifier(identifier);
+ final InstanceIdentifierContext<?> mountPointIdentifier = controllerContext.toMountPointIdentifier(identifier);
mountPoint = mountPointIdentifier.getMountPoint();
modules = controllerContext.getAllModules(mountPoint);
} else {
final String errMsg = "URI has bad format. If operations behind mount point should be showed, URI has to end with ";
+ LOG.debug(errMsg + ControllerContext.MOUNT + " for " + identifier);
throw new RestconfDocumentedException(errMsg + ControllerContext.MOUNT, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
return operationsFromModulesToNormalizedContext(modules, mountPoint);
}
+ private static final Predicate<GroupingBuilder> GROUPING_FILTER = new Predicate<GroupingBuilder>() {
+ @Override
+ public boolean apply(final GroupingBuilder g) {
+ return Draft02.RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName());
+ }
+ };
+
private NormalizedNodeContext operationsFromModulesToNormalizedContext(final Set<Module> modules,
final DOMMountPoint mountPoint) {
- // FIXME find best way to change restconf-netconf yang schema for provide this functionality
- final String errMsg = "We are not able support view operations functionality yet.";
- throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED);
+ final Module restconfModule = getRestconfModule();
+ final ModuleBuilder restConfModuleBuilder = new ModuleBuilder(restconfModule);
+ final Set<GroupingBuilder> gropingBuilders = restConfModuleBuilder.getGroupingBuilders();
+ final Iterable<GroupingBuilder> filteredGroups = Iterables.filter(gropingBuilders, GROUPING_FILTER);
+ final GroupingBuilder restconfGroupingBuilder = Iterables.getFirst(filteredGroups, null);
+ final ContainerSchemaNodeBuilder restContainerSchemaNodeBuilder = (ContainerSchemaNodeBuilder) restconfGroupingBuilder
+ .getDataChildByName(Draft02.RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE);
+ final ContainerSchemaNodeBuilder containerSchemaNodeBuilder = (ContainerSchemaNodeBuilder) restContainerSchemaNodeBuilder
+ .getDataChildByName(Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE);
+
+ final ContainerSchemaNodeBuilder fakeOperationsSchemaNodeBuilder = containerSchemaNodeBuilder;
+ final SchemaPath fakeSchemaPath = fakeOperationsSchemaNodeBuilder.getPath().createChild(QName.create("dummy"));
+
+ final List<LeafNode<Object>> operationsAsData = new ArrayList<>();
+
+ for (final Module module : modules) {
+ final Set<RpcDefinition> rpcs = module.getRpcs();
+ for (final RpcDefinition rpc : rpcs) {
+ final QName rpcQName = rpc.getQName();
+ final String name = module.getName();
+
+ final QName qName = QName.create(restconfModule.getQNameModule(), rpcQName.getLocalName());
+ final LeafSchemaNodeBuilder leafSchemaNodeBuilder = new LeafSchemaNodeBuilder(name, 0, qName, fakeSchemaPath);
+ final LeafSchemaNodeBuilder fakeRpcSchemaNodeBuilder = leafSchemaNodeBuilder;
+ fakeRpcSchemaNodeBuilder.setAugmenting(true);
+
+ final EmptyType instance = EmptyType.getInstance();
+ fakeRpcSchemaNodeBuilder.setType(instance);
+ final LeafSchemaNode fakeRpcSchemaNode = fakeRpcSchemaNodeBuilder.build();
+ fakeOperationsSchemaNodeBuilder.addChildNode(fakeRpcSchemaNode);
+
+ final LeafNode<Object> leaf = Builders.leafBuilder(fakeRpcSchemaNode).build();
+ operationsAsData.add(leaf);
+ }
+ }
+
+ final ContainerSchemaNode operContainerSchemaNode = fakeOperationsSchemaNodeBuilder.build();
+ final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> operContainerNode = Builders.containerBuilder(operContainerSchemaNode);
+
+ for (final LeafNode<Object> oper : operationsAsData) {
+ operContainerNode.withChild(oper);
+ }
+
+ final Set<Module> fakeRpcModules = Collections.singleton(restConfModuleBuilder.build());
+
+ final YangParserImpl yangParser = new YangParserImpl();
+ final SchemaContext fakeSchemaCx = yangParser.resolveSchemaContext(fakeRpcModules);
+
+ final InstanceIdentifierContext<?> fakeIICx = new InstanceIdentifierContext<>(null, operContainerSchemaNode, mountPoint, fakeSchemaCx);
+
+ return new NormalizedNodeContext(fakeIICx, operContainerNode.build());
}
private Module getRestconfModule() {
final Module restconfModule = controllerContext.getRestconfModule();
if (restconfModule == null) {
+ LOG.debug("ietf-restconf module was not found.");
throw new RestconfDocumentedException("ietf-restconf module was not found.", ErrorType.APPLICATION,
ErrorTag.OPERATION_NOT_SUPPORTED);
}
final Iterable<String> split = splitter.split(moduleNameAndRevision);
final List<String> pathArgs = Lists.<String> newArrayList(split);
if (pathArgs.size() < 2) {
+ LOG.debug("URI has bad format. It should be \'moduleName/yyyy-MM-dd\' " + identifier);
throw new RestconfDocumentedException(
"URI has bad format. End of URI should be in format \'moduleName/yyyy-MM-dd\'", ErrorType.PROTOCOL,
ErrorTag.INVALID_VALUE);
final Date moduleRevision = REVISION_FORMAT.parse(revision);
return QName.create(null, moduleRevision, moduleName);
} catch (final ParseException e) {
+ LOG.debug("URI has bad format. It should be \'moduleName/yyyy-MM-dd\' " + identifier);
throw new RestconfDocumentedException("URI has bad format. It should be \'moduleName/yyyy-MM-dd\'",
ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
if (identifier.contains(MOUNT_POINT_MODULE_NAME) && mountPoint != null) {
final Optional<DOMRpcService> mountRpcServices = mountPoint.getService(DOMRpcService.class);
if ( ! mountRpcServices.isPresent()) {
+ LOG.debug("Error: Rpc service is missing.");
throw new RestconfDocumentedException("Rpc service is missing.");
}
schemaContext = mountPoint.getSchemaContext();
}
return new NormalizedNodeContext(new InstanceIdentifierContext<RpcDefinition>(null,
- resultNodeSchema, mountPoint, schemaContext), resultData);
+ resultNodeSchema, mountPoint, schemaContext), resultData,
+ QueryParametersParser.parseWriterParameters(uriInfo));
}
private DOMRpcResult checkRpcResponse(final CheckedFuture<DOMRpcResult, DOMRpcException> response) {
if (retValue.getErrors() == null || retValue.getErrors().isEmpty()) {
return retValue;
}
+ LOG.debug("RpcError message", retValue.getErrors());
throw new RestconfDocumentedException("RpcError message", null, retValue.getErrors());
- }
- catch (final InterruptedException e) {
- throw new RestconfDocumentedException(
- "The operation was interrupted while executing and did not complete.", ErrorType.RPC,
- ErrorTag.PARTIAL_OPERATION);
- }
- catch (final ExecutionException e) {
+ } catch (final InterruptedException e) {
+ final String errMsg = "The operation was interrupted while executing and did not complete.";
+ LOG.debug("Rpc Interrupt - " + errMsg, e);
+ throw new RestconfDocumentedException(errMsg, ErrorType.RPC, ErrorTag.PARTIAL_OPERATION);
+ } catch (final ExecutionException e) {
+ LOG.debug("Execution RpcError: ", e);
Throwable cause = e.getCause();
- if (cause instanceof CancellationException) {
- throw new RestconfDocumentedException("The operation was cancelled while executing.", ErrorType.RPC,
- ErrorTag.PARTIAL_OPERATION);
- } else if (cause != null) {
+ if (cause != null) {
while (cause.getCause() != null) {
cause = cause.getCause();
}
throw new RestconfDocumentedException(cause.getMessage(), ErrorType.PROTOCOL,
ErrorTag.INVALID_VALUE);
}
-
- throw new RestconfDocumentedException("The operation encountered an unexpected error while executing.",
- cause);
+ throw new RestconfDocumentedException("The operation encountered an unexpected error while executing.",cause);
} else {
- throw new RestconfDocumentedException("The operation encountered an unexpected error while executing.",
- e);
+ throw new RestconfDocumentedException("The operation encountered an unexpected error while executing.",e);
}
+ } catch (final CancellationException e) {
+ final String errMsg = "The operation was cancelled while executing.";
+ LOG.debug("Cancel RpcExecution: " + errMsg, e);
+ throw new RestconfDocumentedException(errMsg, ErrorType.RPC, ErrorTag.PARTIAL_OPERATION);
}
}
final Object pathValue = path.isPresent() ? path.get().getValue() : null;
if (!(pathValue instanceof YangInstanceIdentifier)) {
- throw new RestconfDocumentedException("Instance identifier was not normalized correctly.",
- ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
+ final String errMsg = "Instance identifier was not normalized correctly ";
+ LOG.debug(errMsg + rpcQName);
+ throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED);
}
final YangInstanceIdentifier pathIdentifier = ((YangInstanceIdentifier) pathValue);
String streamName = null;
- if (!Iterables.isEmpty(pathIdentifier.getPathArguments())) {
+ if (!pathIdentifier.isEmpty()) {
final String fullRestconfIdentifier = controllerContext.toFullRestconfIdentifier(pathIdentifier, null);
- LogicalDatastoreType datastore = parseEnumTypeParameter(value, LogicalDatastoreType.class,
- DATASTORE_PARAM_NAME);
+ LogicalDatastoreType datastore = parseEnumTypeParameter(value, LogicalDatastoreType.class, DATASTORE_PARAM_NAME);
datastore = datastore == null ? DEFAULT_DATASTORE : datastore;
DataChangeScope scope = parseEnumTypeParameter(value, DataChangeScope.class, SCOPE_PARAM_NAME);
}
if (Strings.isNullOrEmpty(streamName)) {
- throw new RestconfDocumentedException(
- "Path is empty or contains value node which is not Container or List build-in type.",
- ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ final String errMsg = "Path is empty or contains value node which is not Container or List build-in type.";
+ LOG.debug(errMsg + pathIdentifier);
+ throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
final QName outputQname = QName.create(rpcQName, "output");
.withChild(ImmutableNodes.leafNode(streamNameQname, streamName)).build();
if (!Notificator.existListenerFor(streamName)) {
- final YangInstanceIdentifier normalizedPathIdentifier = controllerContext.toNormalized(pathIdentifier);
- Notificator.createListener(normalizedPathIdentifier, streamName);
+ Notificator.createListener(pathIdentifier, streamName);
}
final DOMRpcResult defaultDOMRpcResult = new DefaultDOMRpcResult(output);
final SchemaContext schemaContext;
if (identifier.contains(ControllerContext.MOUNT)) {
// mounted RPC call - look up mount instance.
- final InstanceIdentifierContext mountPointId = controllerContext.toMountPointIdentifier(identifier);
+ final InstanceIdentifierContext<?> mountPointId = controllerContext.toMountPointIdentifier(identifier);
mountPoint = mountPointId.getMountPoint();
schemaContext = mountPoint.getSchemaContext();
final int startOfRemoteRpcName = identifier.lastIndexOf(ControllerContext.MOUNT)
} else if (identifier.indexOf("/") != CHAR_NOT_FOUND) {
final String slashErrorMsg = String.format("Identifier %n%s%ncan\'t contain slash "
+ "character (/).%nIf slash is part of identifier name then use %%2F placeholder.", identifier);
+ LOG.debug(slashErrorMsg);
throw new RestconfDocumentedException(slashErrorMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
} else {
identifierEncoded = identifier;
}
if (rpc == null) {
+ LOG.debug("RPC " + identifierDecoded + " does not exist.");
throw new RestconfDocumentedException("RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT);
}
if (rpc.getInput() != null) {
+ LOG.debug("RPC " + rpc + " does not need input value.");
// FIXME : find a correct Error from specification
throw new IllegalStateException("RPC " + rpc + " does'n need input value!");
}
resultNodeSchema = rpcDataSchemaNode.getDataChildByName(result.getResult().getNodeType());
}
- return new NormalizedNodeContext(new InstanceIdentifierContext(null, resultNodeSchema, mountPoint,
- schemaContext), resultData);
+ return new NormalizedNodeContext(new InstanceIdentifierContext<>(null, resultNodeSchema, mountPoint,
+ schemaContext), resultData, QueryParametersParser.parseWriterParameters(uriInfo));
}
private RpcDefinition findRpc(final SchemaContext schemaContext, final String identifierDecoded) {
final String[] splittedIdentifier = identifierDecoded.split(":");
if (splittedIdentifier.length != 2) {
- throw new RestconfDocumentedException(identifierDecoded
- + " couldn't be splitted to 2 parts (module:rpc name)", ErrorType.APPLICATION,
- ErrorTag.INVALID_VALUE);
+ final String errMsg = identifierDecoded + " couldn't be splitted to 2 parts (module:rpc name)";
+ LOG.debug(errMsg);
+ throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.INVALID_VALUE);
}
for (final Module module : schemaContext.getModules()) {
if (module.getName().equals(splittedIdentifier[0])) {
@Override
public NormalizedNodeContext readConfigurationData(final String identifier, final UriInfo uriInfo) {
- final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+ final InstanceIdentifierContext<?> iiWithData = controllerContext.toInstanceIdentifier(identifier);
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
NormalizedNode<?, ?> data = null;
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
data = broker.readConfigurationData(normalizedII);
}
if(data == null) {
- throw new RestconfDocumentedException(
- "Request could not be completed because the relevant data model content does not exist.",
- ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
- }
- return new NormalizedNodeContext(iiWithData, data);
- }
-
- private Integer parseDepthParameter(final UriInfo info) {
- final String param = info.getQueryParameters(false).getFirst(UriParameters.DEPTH.toString());
- if (Strings.isNullOrEmpty(param) || "unbounded".equals(param)) {
- return null;
- }
-
- try {
- final Integer depth = Integer.valueOf(param);
- if (depth < 1) {
- throw new RestconfDocumentedException(new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- "Invalid depth parameter: " + depth, null,
- "The depth parameter must be an integer > 1 or \"unbounded\""));
- }
-
- return depth;
- } catch (final NumberFormatException e) {
- throw new RestconfDocumentedException(new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- "Invalid depth parameter: " + e.getMessage(), null,
- "The depth parameter must be an integer > 1 or \"unbounded\""));
+ final String errMsg = "Request could not be completed because the relevant data model content does not exist ";
+ LOG.debug(errMsg + identifier);
+ throw new RestconfDocumentedException(errMsg, ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
}
+ return new NormalizedNodeContext(iiWithData, data, QueryParametersParser.parseWriterParameters(uriInfo));
}
@Override
- public NormalizedNodeContext readOperationalData(final String identifier, final UriInfo info) {
- final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+ public NormalizedNodeContext readOperationalData(final String identifier, final UriInfo uriInfo) {
+ final InstanceIdentifierContext<?> iiWithData = controllerContext.toInstanceIdentifier(identifier);
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
NormalizedNode<?, ?> data = null;
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
data = broker.readOperationalData(normalizedII);
}
if(data == null) {
- throw new RestconfDocumentedException(
- "Request could not be completed because the relevant data model content does not exist.",
- ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
+ final String errMsg = "Request could not be completed because the relevant data model content does not exist ";
+ LOG.debug(errMsg + identifier);
+ throw new RestconfDocumentedException(errMsg , ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
}
- return new NormalizedNodeContext(iiWithData, data);
- }
-
- private boolean parsePrettyPrintParameter(final UriInfo info) {
- final String param = info.getQueryParameters(false).getFirst(UriParameters.PRETTY_PRINT.toString());
- return Boolean.parseBoolean(param);
+ return new NormalizedNodeContext(iiWithData, data, QueryParametersParser.parseWriterParameters(uriInfo));
}
@Override
public Response updateConfigurationData(final String identifier, final NormalizedNodeContext payload) {
Preconditions.checkNotNull(identifier);
- final InstanceIdentifierContext<DataSchemaNode> iiWithData =
- (InstanceIdentifierContext<DataSchemaNode>) payload.getInstanceIdentifierContext();
+ final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
validateInput(iiWithData.getSchemaNode(), payload);
validateTopLevelNodeName(payload, iiWithData.getInstanceIdentifier());
- validateListKeysEqualityInPayloadAndUri(iiWithData, payload.getData());
+ validateListKeysEqualityInPayloadAndUri(payload);
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
if (mountPoint != null) {
broker.commitConfigurationDataPut(mountPoint, normalizedII, payload.getData()).checkedGet();
} else {
- broker.commitConfigurationDataPut(normalizedII, payload.getData()).checkedGet();
+ broker.commitConfigurationDataPut(controllerContext.getGlobalSchema(), normalizedII, payload.getData()).checkedGet();
}
break;
} catch (final TransactionCommitFailedException e) {
if(e instanceof OptimisticLockFailedException) {
if(--tries <= 0) {
- LOG.debug("Got OptimisticLockFailedException on last try - failing");
+ LOG.debug("Got OptimisticLockFailedException on last try - failing " + identifier);
throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
}
- LOG.debug("Got OptimisticLockFailedException - trying again");
+ LOG.debug("Got OptimisticLockFailedException - trying again " + identifier);
} else {
+ LOG.debug("Update ConfigDataStore fail " + identifier, e);
throw new RestconfDocumentedException(e.getMessage(), e, e.getErrorList());
}
+ } catch (Exception e) {
+ final String errMsg = "Error updating data ";
+ LOG.debug(errMsg + identifier, e);
+ throw new RestconfDocumentedException(errMsg, e);
}
}
final YangInstanceIdentifier identifier) {
final String payloadName = node.getData().getNodeType().getLocalName();
- final Iterator<PathArgument> pathArguments = identifier.getReversePathArguments().iterator();
//no arguments
- if ( ! pathArguments.hasNext()) {
+ if (identifier.isEmpty()) {
//no "data" payload
- if ( ! node.getData().getNodeType().equals(NETCONF_BASE_QNAME)) {
+ if (!node.getData().getNodeType().equals(NETCONF_BASE_QNAME)) {
throw new RestconfDocumentedException("Instance identifier has to contain at least one path argument",
ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
//any arguments
} else {
- final String identifierName = pathArguments.next().getNodeType().getLocalName();
- if ( ! payloadName.equals(identifierName)) {
+ final String identifierName = identifier.getLastPathArgument().getNodeType().getLocalName();
+ if (!payloadName.equals(identifierName)) {
throw new RestconfDocumentedException("Payload name (" + payloadName
+ ") is different from identifier name (" + identifierName + ")", ErrorType.PROTOCOL,
ErrorTag.MALFORMED_MESSAGE);
* if key values or key count in payload and URI isn't equal
*
*/
- private void validateListKeysEqualityInPayloadAndUri(final InstanceIdentifierContext<DataSchemaNode> iiWithData,
- final NormalizedNode<?, ?> payload) {
- if (iiWithData.getSchemaNode() instanceof ListSchemaNode) {
- final List<QName> keyDefinitions = ((ListSchemaNode) iiWithData.getSchemaNode()).getKeyDefinition();
- final PathArgument lastPathArgument = iiWithData.getInstanceIdentifier().getLastPathArgument();
- if (lastPathArgument instanceof NodeIdentifierWithPredicates) {
- final Map<QName, Object> uriKeyValues = ((NodeIdentifierWithPredicates) lastPathArgument)
- .getKeyValues();
- isEqualUriAndPayloadKeyValues(uriKeyValues, payload, keyDefinitions);
+ private static void validateListKeysEqualityInPayloadAndUri(final NormalizedNodeContext payload) {
+ Preconditions.checkArgument(payload != null);
+ final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
+ final PathArgument lastPathArgument = iiWithData.getInstanceIdentifier().getLastPathArgument();
+ final SchemaNode schemaNode = iiWithData.getSchemaNode();
+ final NormalizedNode<?, ?> data = payload.getData();
+ if (schemaNode instanceof ListSchemaNode) {
+ final List<QName> keyDefinitions = ((ListSchemaNode) schemaNode).getKeyDefinition();
+ if (lastPathArgument instanceof NodeIdentifierWithPredicates && data instanceof MapEntryNode) {
+ final Map<QName, Object> uriKeyValues = ((NodeIdentifierWithPredicates) lastPathArgument).getKeyValues();
+ isEqualUriAndPayloadKeyValues(uriKeyValues, (MapEntryNode) data, keyDefinitions);
}
}
}
- private void isEqualUriAndPayloadKeyValues(final Map<QName, Object> uriKeyValues, final NormalizedNode<?, ?> payload,
- final List<QName> keyDefinitions) {
+ private static void isEqualUriAndPayloadKeyValues(final Map<QName, Object> uriKeyValues,
+ final MapEntryNode payload, final List<QName> keyDefinitions) {
+
+ final Map<QName, Object> mutableCopyUriKeyValues = Maps.newHashMap(uriKeyValues);
for (final QName keyDefinition : keyDefinitions) {
- final Object uriKeyValue = uriKeyValues.get(keyDefinition);
+ final Object uriKeyValue = mutableCopyUriKeyValues.remove(keyDefinition);
// should be caught during parsing URI to InstanceIdentifier
- if (uriKeyValue == null) {
- final String errMsg = "Missing key " + keyDefinition + " in URI.";
- throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ RestconfValidationUtils.checkDocumentedError(uriKeyValue != null, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING,
+ "Missing key " + keyDefinition + " in URI.");
+
+ final Object dataKeyValue = payload.getIdentifier().getKeyValues().get(keyDefinition);
+
+ if ( ! uriKeyValue.equals(dataKeyValue)) {
+ final String errMsg = "The value '" + uriKeyValue + "' for key '" + keyDefinition.getLocalName() +
+ "' specified in the URI doesn't match the value '" + dataKeyValue + "' specified in the message body. ";
+ throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
- // TODO thing about the possibility to fix
-// final List<SimpleNode<?>> payloadKeyValues = payload.getSimpleNodesByName(keyDefinition.getLocalName());
-// if (payloadKeyValues.isEmpty()) {
-// final String errMsg = "Missing key " + keyDefinition.getLocalName() + " in the message body.";
-// throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
-// }
-//
-// final Object payloadKeyValue = payloadKeyValues.iterator().next().getValue();
-// if (!uriKeyValue.equals(payloadKeyValue)) {
-// final String errMsg = "The value '" + uriKeyValue + "' for key '" + keyDefinition.getLocalName() +
-// "' specified in the URI doesn't match the value '" + payloadKeyValue + "' specified in the message body. ";
-// throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
-// }
}
}
if (payloadNodeQname.compareTo(yangIdent.getLastPathArgument().getNodeType()) > 0) {
return yangIdent;
}
- final InstanceIdentifierContext parentContext = payload.getInstanceIdentifierContext();
+ final InstanceIdentifierContext<?> parentContext = payload.getInstanceIdentifierContext();
final SchemaNode parentSchemaNode = parentContext.getSchemaNode();
if(parentSchemaNode instanceof DataNodeContainer) {
final DataNodeContainer cast = (DataNodeContainer) parentSchemaNode;
if (parentSchemaNode instanceof RpcDefinition) {
return yangIdent;
}
- final String errMsg = "Error parsing input: DataSchemaNode has not children";
+ final String errMsg = "Error parsing input: DataSchemaNode has not children ";
+ LOG.info(errMsg + yangIdent);
throw new RestconfDocumentedException(errMsg, ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
throw new RestconfDocumentedException("Input is required.", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
}
- final URI payloadNS = payload.getData().getNodeType().getNamespace();
- if (payloadNS == null) {
- throw new RestconfDocumentedException(
- "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
- ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE);
- }
+ // FIXME: move this to parsing stage (we can have augmentation nodes here which do not have namespace)
+// final URI payloadNS = payload.getData().getNodeType().getNamespace();
+// if (payloadNS == null) {
+// throw new RestconfDocumentedException(
+// "Data has bad format. Root element node must have namespace (XML format) or module name(JSON format)",
+// ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE);
+// }
final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
- final InstanceIdentifierContext<DataSchemaNode> iiWithData = (InstanceIdentifierContext<DataSchemaNode>) payload.getInstanceIdentifierContext();
+ final InstanceIdentifierContext<?> iiWithData = payload.getInstanceIdentifierContext();
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
- final YangInstanceIdentifier resultII;
try {
if (mountPoint != null) {
broker.commitConfigurationDataPost(mountPoint, normalizedII, payload.getData()).checkedGet();
} else {
- broker.commitConfigurationDataPost(normalizedII, payload.getData()).checkedGet();
+ broker.commitConfigurationDataPost(controllerContext.getGlobalSchema(), normalizedII, payload.getData()).checkedGet();
}
} catch(final RestconfDocumentedException e) {
throw e;
} catch (final Exception e) {
- throw new RestconfDocumentedException("Error creating data", e);
+ final String errMsg = "Error creating data ";
+ LOG.info(errMsg + (uriInfo != null ? uriInfo.getPath() : ""), e);
+ throw new RestconfDocumentedException(errMsg, e);
}
final ResponseBuilder responseBuilder = Response.status(Status.NO_CONTENT);
try {
uriBuilder.path(controllerContext.toFullRestconfIdentifier(normalizedII, mountPoint));
} catch (final Exception e) {
- LOG.debug("Location for instance identifier"+normalizedII+"wasn't created", e);
+ LOG.info("Location for instance identifier" + normalizedII + "wasn't created", e);
return null;
}
return uriBuilder.build();
@Override
public Response deleteConfigurationData(final String identifier) {
- final InstanceIdentifierContext<DataSchemaNode> iiWithData = controllerContext.toInstanceIdentifier(identifier);
+ final InstanceIdentifierContext<?> iiWithData = controllerContext.toInstanceIdentifier(identifier);
final DOMMountPoint mountPoint = iiWithData.getMountPoint();
final YangInstanceIdentifier normalizedII = iiWithData.getInstanceIdentifier();
if (searchedException.isPresent()) {
throw new RestconfDocumentedException("Data specified for deleting doesn't exist.", ErrorType.APPLICATION, ErrorTag.DATA_MISSING);
}
- throw new RestconfDocumentedException("Error while deleting data", e);
+ final String errMsg = "Error while deleting data";
+ LOG.info(errMsg, e);
+ throw new RestconfDocumentedException(errMsg, e);
}
return Response.status(Status.OK).build();
}
return result;
}
- private boolean endsWithMountPoint(final String identifier) {
- return identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/");
- }
-
- private String addMountPointIdentifier(final String identifier) {
- final boolean endsWith = identifier.endsWith("/");
- if (endsWith) {
- return (identifier + ControllerContext.MOUNT);
- }
-
- return identifier + "/" + ControllerContext.MOUNT;
- }
-
- private TypeDef typeDefinition(final TypeDefinition<?> type, final QName nodeQName) {
- TypeDefinition<?> baseType = type;
- QName qName = nodeQName;
- while (baseType.getBaseType() != null) {
- if (baseType instanceof ExtendedType) {
- qName = baseType.getQName();
- }
- baseType = baseType.getBaseType();
- }
-
- return new TypeDef(baseType, qName);
-
- }
-
- private TypeDef typeDefinition(final DataSchemaNode node) {
- if (node instanceof LeafListSchemaNode) {
- return typeDefinition(((LeafListSchemaNode)node).getType(), node.getQName());
- } else if (node instanceof LeafSchemaNode) {
- return typeDefinition(((LeafSchemaNode)node).getType(), node.getQName());
- } else if (node instanceof AnyXmlSchemaNode) {
- return null;
- } else {
- throw new IllegalArgumentException("Unhandled parameter types: " + Arrays.<Object> asList(node).toString());
- }
- }
-
- private InstanceIdentifierContext normalizeInstanceIdentifierWithSchemaNode(
- final InstanceIdentifierContext iiWithSchemaNode) {
- return normalizeInstanceIdentifierWithSchemaNode(iiWithSchemaNode, false);
- }
-
- private InstanceIdentifierContext normalizeInstanceIdentifierWithSchemaNode(
- final InstanceIdentifierContext iiWithSchemaNode, final boolean unwrapLastListNode) {
- return new InstanceIdentifierContext(instanceIdentifierToReadableFormForNormalizeNode(
- iiWithSchemaNode.getInstanceIdentifier(), unwrapLastListNode), iiWithSchemaNode.getSchemaNode(),
- iiWithSchemaNode.getMountPoint(),iiWithSchemaNode.getSchemaContext());
- }
-
- private YangInstanceIdentifier instanceIdentifierToReadableFormForNormalizeNode(
- final YangInstanceIdentifier instIdentifier, final boolean unwrapLastListNode) {
- Preconditions.checkNotNull(instIdentifier, "Instance identifier can't be null");
- final List<PathArgument> result = new ArrayList<PathArgument>();
- final Iterator<PathArgument> iter = instIdentifier.getPathArguments().iterator();
- while (iter.hasNext()) {
- final PathArgument pathArgument = iter.next();
- if (pathArgument instanceof NodeIdentifierWithPredicates && (iter.hasNext() || unwrapLastListNode)) {
- result.add(new YangInstanceIdentifier.NodeIdentifier(pathArgument.getNodeType()));
- }
- result.add(pathArgument);
- }
- return YangInstanceIdentifier.create(result);
- }
-
- private boolean isDataContainerNode(final DataSchemaNode schemaNode) {
- if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode) {
- return true;
- }
- return false;
- }
-
public BigInteger getOperationalReceived() {
// TODO Auto-generated method stub
return null;