aboutsummaryrefslogtreecommitdiffstats
path: root/rest-services/cbs-client/src/main/java/org/onap/dcaegen2/services/sdk/rest/services/cbs/client/api/listener/MerkleTreeParser.java
blob: dfd0e2f7183c9e4732dcfa219cbfdad399678968 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * ============LICENSE_START====================================
 * DCAEGEN2-SERVICES-SDK
 * =========================================================
 * Copyright (C) 2019 Nokia. All rights reserved.
 * =========================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============LICENSE_END=====================================
 */
package org.onap.dcaegen2.services.sdk.rest.services.cbs.client.api.listener;

import static java.lang.String.valueOf;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.vavr.collection.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.jetbrains.annotations.NotNull;


/**
 * Class responsible for creating MerkleTree structure from JsonObject.
 *
 * @since 1.1.2
 */
class MerkleTreeParser {

    /**
     * <p> Method used to parse {@link JsonObject} into {@link MerkleTree} structure.</p>
     * <p> The algorithm will recursively create mapping of (path in tree)->(value) from JsonObject
     * and use it to create MerkleTree by means of {@link MerkleTree#add(List, Object)} method. </p>
     * <p> Each JsonObject will append it's key to path until value of primitive type is encountered.
     * For each JsonArray element artificial path is created by creating lables from sequential integers.
     * This results in array split into multiple nodes in MerkleTree structure.</p>
     *
     * <p>Example. For JsonObject:
     * <pre>
     * {
     *      "p1": "v1",
     *      "p2": ["v2", "v3"]
     *      "p3": {
     *          "p4": "v4"
     *      }
     * }
     * </pre>
     * following map would be created:</p>
     * <pre>
     *  "v1" <- ["p1"]
     *  "v2" <- ["p2", "0"]
     *  "v3" <- ["p2", "1"]
     *  "v4" <- ["p3", "p4"]
     * </pre>
     *
     * @param json JsonObject to be parsed
     * @since 1.1.2
     */
    MerkleTree<String> fromJsonObject(final @NotNull JsonObject json) {
        MerkleTree<String> tree = MerkleTree.emptyWithDefaultDigest(String::getBytes);
        for (Entry<String, JsonElement> entry : json.entrySet()) {
            tree = treeEnhancedWithEntry(tree, entry);
        }

        return tree;
    }

    private MerkleTree<String> treeEnhancedWithEntry(final MerkleTree<String> tree,
                                                     final Entry<String, JsonElement> entry) {
        return createTreeFromValuesPaths(tree, pathsToValues(entry, List.empty()));
    }

    private Map<List<String>, String> pathsToValues(Entry<String, JsonElement> entry, List<String> elementPathPrefix) {
        return pathsToValuesFromJsonElement(entry.getKey(), entry.getValue(), elementPathPrefix);
    }

    private Map<List<String>, String> pathsToValuesFromJsonElement(final String jsonKey,
                                                                   final JsonElement element,
                                                                   final List<String> elementPathPrefix) {
        final HashMap<List<String>, String> pathToValue = new HashMap<>();
        final List<String> newPrefix = elementPathPrefix.append(jsonKey);

        if (element.isJsonObject()) {
            element.getAsJsonObject()
                    .entrySet()
                    .forEach(entry -> pathToValue.putAll(pathsToValues(entry, newPrefix)));
        } else if (element.isJsonArray()) {
            pathToValue.putAll(handleArray(newPrefix, element.getAsJsonArray()));
        } else if (element.isJsonPrimitive()) {
            pathToValue.put(newPrefix, element.getAsString());
        } else if (element.isJsonNull()) {
            pathToValue.put(newPrefix, null);
        }
        return pathToValue;
    }

    private HashMap<List<String>, String> handleArray(List<String> newPrefix, JsonArray jsonArray) {
        final HashMap<List<String>, String> hashMap = new HashMap<>();
        int labelIndex = 0;

        for (JsonElement jsonElement : jsonArray) {
            String jsonKey = valueOf(labelIndex++);
            hashMap.putAll(pathsToValuesFromJsonElement(jsonKey, jsonElement, newPrefix));
        }
        return hashMap;
    }

    private MerkleTree<String> createTreeFromValuesPaths(MerkleTree<String> tree,
                                                         final Map<List<String>, String> pathToValue) {
        for (Entry<List<String>, String> entry : pathToValue.entrySet()) {
            List<String> path = entry.getKey();
            String value = entry.getValue();
            tree = tree.add(path, value);
        }
        return tree;
    }
}