import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.TimeZone;
+import javax.annotation.Nonnull;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
import org.opendaylight.netconf.sal.restconf.impl.PATCHContext;
import org.opendaylight.netconf.sal.restconf.impl.PATCHStatusContext;
import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
+import org.opendaylight.netconf.sal.restconf.impl.WriterParameters;
+import org.opendaylight.restconf.RestConnectorProvider;
import org.opendaylight.restconf.common.references.SchemaContextRef;
+import org.opendaylight.restconf.handlers.DOMMountPointServiceHandler;
import org.opendaylight.restconf.handlers.SchemaContextHandler;
import org.opendaylight.restconf.handlers.TransactionChainHandler;
import org.opendaylight.restconf.restful.services.api.RestconfDataService;
import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
import org.opendaylight.restconf.restful.utils.DeleteDataTransactionUtil;
+import org.opendaylight.restconf.restful.utils.PatchDataTransactionUtil;
import org.opendaylight.restconf.restful.utils.PostDataTransactionUtil;
import org.opendaylight.restconf.restful.utils.PutDataTransactionUtil;
import org.opendaylight.restconf.restful.utils.ReadDataTransactionUtil;
private final static Logger LOG = LoggerFactory.getLogger(RestconfDataServiceImpl.class);
- private SchemaContextHandler schemaContextHandler;
- private TransactionChainHandler transactionChainHandler;
+ private final SchemaContextHandler schemaContextHandler;
+ private final TransactionChainHandler transactionChainHandler;
+ private final DOMMountPointServiceHandler mountPointServiceHandler;
+
+ public RestconfDataServiceImpl(final SchemaContextHandler schemaContextHandler,
+ final TransactionChainHandler transactionChainHandler,
+ final DOMMountPointServiceHandler mountPointServiceHandler) {
+ this.schemaContextHandler = schemaContextHandler;
+ this.transactionChainHandler = transactionChainHandler;
+ this.mountPointServiceHandler = mountPointServiceHandler;
+ }
+
+ @Override
+ public Response readData(final UriInfo uriInfo) {
+ return readData(null, uriInfo);
+ }
@Override
- public NormalizedNodeContext readData(final String identifier, final UriInfo uriInfo) {
- Preconditions.checkNotNull(identifier);
+ public Response readData(final String identifier, final UriInfo uriInfo) {
final SchemaContextRef schemaContextRef = new SchemaContextRef(this.schemaContextHandler.get());
+ final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(
+ identifier, schemaContextRef.get(), Optional.of(this.mountPointServiceHandler.get()));
- final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier, schemaContextRef.get());
- final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
- final String value = uriInfo.getQueryParameters().getFirst(RestconfDataServiceConstant.CONTENT);
+ final WriterParameters parameters = ReadDataTransactionUtil.parseUriParameters(
+ instanceIdentifier, uriInfo);
- DOMDataReadWriteTransaction transaction = null;
+ final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
+ final DOMTransactionChain transactionChain;
if (mountPoint == null) {
- transaction = this.transactionChainHandler.get().newReadWriteTransaction();
+ transactionChain = this.transactionChainHandler.get();
} else {
- transaction = transactionOfMountPoint(mountPoint);
+ transactionChain = transactionChainOfMountPoint(mountPoint);
+ }
+
+ final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
+ instanceIdentifier, mountPoint, transactionChain);
+ final NormalizedNode<?, ?> node = ReadDataTransactionUtil.readData(parameters.getContent(), transactionNode);
+ if (node == null) {
+ throw new RestconfDocumentedException(
+ "Request could not be completed because the relevant data model content does not exist",
+ RestconfError.ErrorType.PROTOCOL,
+ RestconfError.ErrorTag.DATA_MISSING);
+ }
+ final SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
+ dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
+ final String etag = '"' + node.getNodeType().getModule().getFormattedRevision()
+ + node.getNodeType().getLocalName() + '"';
+ final Response resp;
+
+ if ((parameters.getContent().equals(RestconfDataServiceConstant.ReadData.ALL))
+ || parameters.getContent().equals(RestconfDataServiceConstant.ReadData.CONFIG)) {
+ resp = Response.status(200)
+ .entity(new NormalizedNodeContext(instanceIdentifier, node, parameters))
+ .header("ETag", etag)
+ .header("Last-Modified", dateFormatGmt.format(new Date()))
+ .build();
+ } else {
+ resp = Response.status(200)
+ .entity(new NormalizedNodeContext(instanceIdentifier, node, parameters))
+ .build();
}
- final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(instanceIdentifier, mountPoint,
- transaction);
- final NormalizedNode<?, ?> node = ReadDataTransactionUtil.readData(value, transactionNode);
- return new NormalizedNodeContext(instanceIdentifier, node);
+ return resp;
}
@Override
- public Response putData(final String identifier, final NormalizedNodeContext payload) {
- Preconditions.checkNotNull(identifier);
+ public Response putData(final String identifier, final NormalizedNodeContext payload, final UriInfo uriInfo) {
Preconditions.checkNotNull(payload);
+ boolean insert_used = false;
+ boolean point_used = false;
+ String insert = null;
+ String point = null;
+
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "insert":
+ if (!insert_used) {
+ insert_used = true;
+ insert = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Insert parameter can be used only once.");
+ }
+ break;
+ case "point":
+ if (!point_used) {
+ point_used = true;
+ point = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Point parameter can be used only once.");
+ }
+ break;
+ default:
+ throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
+ }
+ }
+
+ checkQueryParams(insert_used, point_used, insert);
+
final InstanceIdentifierContext<? extends SchemaNode> iid = payload
.getInstanceIdentifierContext();
PutDataTransactionUtil.validateListKeysEqualityInPayloadAndUri(payload);
final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
- DOMDataReadWriteTransaction transaction = null;
- SchemaContextRef ref = null;
+ final DOMTransactionChain transactionChain;
+ final SchemaContextRef ref;
if (mountPoint == null) {
- transaction = this.transactionChainHandler.get().newReadWriteTransaction();
+ transactionChain = this.transactionChainHandler.get();
ref = new SchemaContextRef(this.schemaContextHandler.get());
} else {
- transaction = transactionOfMountPoint(mountPoint);
+ transactionChain = transactionChainOfMountPoint(mountPoint);
ref = new SchemaContextRef(mountPoint.getSchemaContext());
}
final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
- payload.getInstanceIdentifierContext(), mountPoint, transaction);
- return PutDataTransactionUtil.putData(payload, ref, transactionNode);
+ payload.getInstanceIdentifierContext(), mountPoint, transactionChain);
+ return PutDataTransactionUtil.putData(payload, ref, transactionNode, insert, point);
+ }
+
+ private void checkQueryParams(final boolean insert_used, final boolean point_used, final String insert) {
+ if (point_used && !insert_used) {
+ throw new RestconfDocumentedException("Point parameter can't be used without Insert parameter.");
+ }
+ if (point_used && (insert.equals("first") || insert.equals("last"))) {
+ throw new RestconfDocumentedException(
+ "Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
+ }
}
@Override
public Response postData(final NormalizedNodeContext payload, final UriInfo uriInfo) {
Preconditions.checkNotNull(payload);
+ boolean insert_used = false;
+ boolean point_used = false;
+ String insert = null;
+ String point = null;
+
+ for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
+ switch (entry.getKey()) {
+ case "insert":
+ if (!insert_used) {
+ insert_used = true;
+ insert = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Insert parameter can be used only once.");
+ }
+ break;
+ case "point":
+ if (!point_used) {
+ point_used = true;
+ point = entry.getValue().iterator().next();
+ } else {
+ throw new RestconfDocumentedException("Point parameter can be used only once.");
+ }
+ break;
+ default:
+ throw new RestconfDocumentedException("Bad parameter for post: " + entry.getKey());
+ }
+ }
+
+ checkQueryParams(insert_used, point_used, insert);
+
final DOMMountPoint mountPoint = payload.getInstanceIdentifierContext().getMountPoint();
- DOMDataReadWriteTransaction transaction = null;
- SchemaContextRef ref = null;
+ final DOMTransactionChain transactionChain;
+ final SchemaContextRef ref;
if (mountPoint == null) {
- transaction = this.transactionChainHandler.get().newReadWriteTransaction();
+ transactionChain = this.transactionChainHandler.get();
ref = new SchemaContextRef(this.schemaContextHandler.get());
} else {
- transaction = transactionOfMountPoint(mountPoint);
+ transactionChain = transactionChainOfMountPoint(mountPoint);
ref = new SchemaContextRef(mountPoint.getSchemaContext());
}
final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
- payload.getInstanceIdentifierContext(), mountPoint, transaction);
- return PostDataTransactionUtil.postData(uriInfo, payload, transactionNode, ref);
+ payload.getInstanceIdentifierContext(), mountPoint, transactionChain);
+ return PostDataTransactionUtil.postData(uriInfo, payload, transactionNode, ref, insert, point);
}
@Override
public Response deleteData(final String identifier) {
final SchemaContextRef schemaContextRef = new SchemaContextRef(this.schemaContextHandler.get());
- final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier,
- schemaContextRef.get());
+ final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(
+ identifier, schemaContextRef.get(), Optional.of(this.mountPointServiceHandler.get()));
final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
- DOMDataReadWriteTransaction transaction = null;
+ final DOMTransactionChain transactionChain;
if (mountPoint == null) {
- transaction = this.transactionChainHandler.get().newReadWriteTransaction();
+ transactionChain = this.transactionChainHandler.get();
} else {
- transaction = transactionOfMountPoint(mountPoint);
+ transactionChain = transactionChainOfMountPoint(mountPoint);
}
final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(instanceIdentifier, mountPoint,
- transaction);
+ transactionChain);
return DeleteDataTransactionUtil.deleteData(transactionNode);
}
@Override
public PATCHStatusContext patchData(final String identifier, final PATCHContext context, final UriInfo uriInfo) {
- throw new UnsupportedOperationException("Not yet implemented.");
+ return patchData(context, uriInfo);
}
@Override
public PATCHStatusContext patchData(final PATCHContext context, final UriInfo uriInfo) {
- throw new UnsupportedOperationException("Not yet implemented.");
+ Preconditions.checkNotNull(context);
+ final DOMMountPoint mountPoint = context.getInstanceIdentifierContext().getMountPoint();
+
+ final DOMTransactionChain transactionChain;
+ final SchemaContextRef ref;
+ if (mountPoint == null) {
+ transactionChain = this.transactionChainHandler.get();
+ ref = new SchemaContextRef(this.schemaContextHandler.get());
+ } else {
+ transactionChain = transactionChainOfMountPoint(mountPoint);
+ ref = new SchemaContextRef(mountPoint.getSchemaContext());
+ }
+
+ final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(
+ context.getInstanceIdentifierContext(), mountPoint, transactionChain);
+
+ return PatchDataTransactionUtil.patchData(context, transactionNode, ref);
}
/**
- * Prepare transaction to read data of mount point, if these data are
- * present.
+ * Prepare transaction chain to access data of mount point
* @param mountPoint
- *
- * @param transactionNode
- * - {@link TransactionVarsWrapper} - wrapper for variables
- * @return {@link NormalizedNode}
+ * - mount point reference
+ * @return {@link DOMTransactionChain}
*/
- private static DOMDataReadWriteTransaction transactionOfMountPoint(final DOMMountPoint mountPoint) {
+ private static DOMTransactionChain transactionChainOfMountPoint(@Nonnull final DOMMountPoint mountPoint) {
final Optional<DOMDataBroker> domDataBrokerService = mountPoint.getService(DOMDataBroker.class);
if (domDataBrokerService.isPresent()) {
- return domDataBrokerService.get().newReadWriteTransaction();
+ return domDataBrokerService.get().createTransactionChain(RestConnectorProvider.transactionListener);
} else {
final String errMsg = "DOM data broker service isn't available for mount point "
+ mountPoint.getIdentifier();