import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.ConcurrencyException;
import org.onap.cps.spi.exceptions.CpsPathException;
+import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
+import org.onap.cps.spi.exceptions.DataValidationException;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.DataNodeBuilder;
import org.onap.cps.spi.repository.AnchorRepository;
private FragmentRepository fragmentRepository;
+ private final ObjectMapper objectMapper;
+
/**
* Constructor.
*
this.dataspaceRepository = dataspaceRepository;
this.anchorRepository = anchorRepository;
this.fragmentRepository = fragmentRepository;
+ this.objectMapper = new ObjectMapper();
}
private static final Gson GSON = new GsonBuilder().create();
- private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@\\S+?]){0,1})";
+ private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?]){0,1})";
+ private static final String REG_EX_FOR_LIST_NODE_KEY = "\\[(\\@([^/]*?))+( and)*\\]$";
@Override
public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentXpath,
final CpsPathQuery cpsPathQuery) {
final Set<String> ancestorXpath = new HashSet<>();
final var pattern =
- Pattern.compile("(\\S*\\/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier())
- + REG_EX_FOR_OPTIONAL_LIST_INDEX + "\\/\\S*");
+ Pattern.compile("([\\s\\S]*\\/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier())
+ + REG_EX_FOR_OPTIONAL_LIST_INDEX + "\\/[\\s\\S]*");
for (final FragmentEntity fragmentEntity : fragmentEntities) {
final var matcher = pattern.matcher(fragmentEntity.getXpath());
if (matcher.matches()) {
return ancestorXpath;
}
- private static DataNode toDataNode(final FragmentEntity fragmentEntity,
+ private DataNode toDataNode(final FragmentEntity fragmentEntity,
final FetchDescendantsOption fetchDescendantsOption) {
- final Map<String, Object> leaves = GSON.fromJson(fragmentEntity.getAttributes(), Map.class);
final List<DataNode> childDataNodes = getChildDataNodes(fragmentEntity, fetchDescendantsOption);
+ Map<String, Object> leaves = new HashMap<>();
+ if (fragmentEntity.getAttributes() != null) {
+ try {
+ leaves = objectMapper.readValue(fragmentEntity.getAttributes(), Map.class);
+ } catch (final JsonProcessingException jsonProcessingException) {
+ final String message = "Parsing error occurred while processing fragmentEntity attributes.";
+ log.error(message);
+ throw new DataValidationException(message,
+ jsonProcessingException.getMessage(), jsonProcessingException);
+ }
+ }
return new DataNodeBuilder()
.withXpath(fragmentEntity.getXpath())
.withLeaves(leaves)
.withChildDataNodes(childDataNodes).build();
}
- private static List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity,
+ private List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity,
final FetchDescendantsOption fetchDescendantsOption) {
if (fetchDescendantsOption == INCLUDE_ALL_DESCENDANTS) {
return fragmentEntity.getChildFragments().stream()
fragmentRepository.save(parentEntity);
}
+ @Override
+ @Transactional
+ public void deleteListDataNodes(final String dataspaceName, final String anchorName, final String listNodeXpath) {
+ final var parentNodeXpath = listNodeXpath.substring(0, listNodeXpath.lastIndexOf('/'));
+ final var parentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
+ final var descendantNode = listNodeXpath.substring(listNodeXpath.lastIndexOf('/'));
+ final Matcher descendantNodeHasListNodeKey = Pattern.compile(REG_EX_FOR_LIST_NODE_KEY).matcher(descendantNode);
+
+ final boolean xpathPointsToAValidChildNodeWithKey = parentEntity.getChildFragments().stream().anyMatch(
+ (fragment) -> fragment.getXpath().equals(listNodeXpath));
+
+ final boolean xpathPointsToAValidChildNodeWithoutKey = parentEntity.getChildFragments().stream().anyMatch(
+ (fragment) -> fragment.getXpath().replaceAll(REG_EX_FOR_LIST_NODE_KEY, "").equals(listNodeXpath));
+
+ if ((descendantNodeHasListNodeKey.find() && xpathPointsToAValidChildNodeWithKey)
+ ||
+ (!descendantNodeHasListNodeKey.find() && xpathPointsToAValidChildNodeWithoutKey)) {
+ removeListNodeDescendants(parentEntity, listNodeXpath);
+ } else {
+ throw new DataNodeNotFoundException(parentEntity.getDataspace().getName(),
+ parentEntity.getAnchor().getName(), listNodeXpath);
+ }
+ }
+
private void removeListNodeDescendants(final FragmentEntity parentFragmentEntity, final String listNodeXpath) {
- final String listNodeXpathPrefix = listNodeXpath + "[";
+ final Matcher descendantNodeHasListNodeKey = Pattern.compile(REG_EX_FOR_LIST_NODE_KEY).matcher(listNodeXpath);
+ final String listNodeXpathPrefix = listNodeXpath + (descendantNodeHasListNodeKey.find() ? "" : "[");
if (parentFragmentEntity.getChildFragments()
.removeIf(fragment -> fragment.getXpath().startsWith(listNodeXpathPrefix))) {
fragmentRepository.save(parentFragmentEntity);