2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ============LICENSE_END=========================================================
19 package org.onap.policy.controlloop.utils;
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.LinkedHashMap;
24 import java.util.List;
26 import java.util.Properties;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29 import org.onap.policy.controlloop.ControlLoopException;
30 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
31 import org.onap.policy.controlloop.processor.ControlLoopProcessor;
32 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
39 public class ControlLoopUtils {
41 public static final Logger logger = LoggerFactory.getLogger(ControlLoopUtils.class);
42 private static final Pattern NAME_PAT = Pattern.compile("(.*)\\[(\\d{1,3})\\]");
44 private ControlLoopUtils() {
49 * Get a Control Loop Parameters object from a Tosca Policy.
51 public static ControlLoopParams toControlLoopParams(ToscaPolicy policy) {
53 /* No exceptions are thrown to keep the DRL simpler */
56 return new ControlLoopProcessor(policy).getControlLoopParams();
57 } catch (ControlLoopException | RuntimeException e) {
58 logger.error("Invalid Policy because of {}: {}", e.getMessage(), policy, e);
63 // TODO move the following to policy-common/utils
66 * Converts a set of properties to a Map. Supports json-path style property names with
67 * "." separating components, where components may have an optional subscript.
69 * @param properties properties to be converted
70 * @param prefix properties whose names begin with this prefix are included. The
71 * prefix is stripped from the name before adding the value to the map
72 * @return a hierarchical map representing the properties
74 public static Map<String, Object> toObject(Properties properties, String prefix) {
75 String dottedPrefix = prefix + (prefix.isEmpty() || prefix.endsWith(".") ? "" : ".");
76 int pfxlen = dottedPrefix.length();
78 Map<String, Object> map = new LinkedHashMap<>();
80 for (String name : properties.stringPropertyNames()) {
81 if (name.startsWith(dottedPrefix)) {
82 String[] components = name.substring(pfxlen).split("[.]");
83 setProperty(map, components, properties.getProperty(name));
91 * Sets a property within a hierarchical map.
93 * @param map map into which the value should be placed
94 * @param names property name components
95 * @param value value to be placed into the map
97 private static void setProperty(Map<String, Object> map, String[] names, String value) {
98 Map<String, Object> node = map;
100 final int lastComp = names.length - 1;
102 // process all but the final component
103 for (int comp = 0; comp < lastComp; ++comp) {
104 node = getNode(node, names[comp]);
107 // process the final component
108 String name = names[lastComp];
109 Matcher matcher = NAME_PAT.matcher(name);
111 if (!matcher.matches()) {
113 node.put(name, value);
118 List<Object> array = getArray(node, matcher.group(1));
119 int index = Integer.parseInt(matcher.group(2));
120 expand(array, index);
121 array.set(index, value);
127 * @param map map from which to get the object
128 * @param name name of the element to get from the map, with an optional subscript
131 @SuppressWarnings("unchecked")
132 private static Map<String, Object> getNode(Map<String, Object> map, String name) {
133 Matcher matcher = NAME_PAT.matcher(name);
135 if (!matcher.matches()) {
137 return getObject(map, name);
141 List<Object> array = getArray(map, matcher.group(1));
142 int index = Integer.parseInt(matcher.group(2));
143 expand(array, index);
145 Object item = array.get(index);
146 if (item instanceof Map) {
147 return (Map<String, Object>) item;
150 LinkedHashMap<String, Object> result = new LinkedHashMap<>();
151 array.set(index, result);
157 * Ensures that an array's size is large enough to hold the specified element.
159 * @param array array to be expanded
160 * @param index index of the desired element
162 private static void expand(List<Object> array, int index) {
163 while (array.size() <= index) {
169 * Gets an object (i.e., Map) from a map. If the particular element is not a Map, then
170 * it is replaced with an empty Map.
172 * @param map map from which to get the object
173 * @param name name of the element to get from the map, without any subscript
176 private static Map<String, Object> getObject(Map<String, Object> map, String name) {
177 @SuppressWarnings("unchecked")
178 Map<String, Object> result = (Map<String, Object>) map.compute(name, (key, value) -> {
179 if (value instanceof Map) {
182 return new LinkedHashMap<>();
190 * Gets an array from a map. If the particular element is not an array, then it is
191 * replaced with an empty array.
193 * @param map map from which to get the array
194 * @param name name of the element to get from the map, without any subscript
197 private static List<Object> getArray(Map<String, Object> map, String name) {
198 @SuppressWarnings("unchecked")
199 List<Object> result = (List<Object>) map.compute(name, (key, value) -> {
200 if (value instanceof List) {
203 return new ArrayList<>();
211 * Compresses lists contained within a generic object, removing all {@code null}
214 * @param object object to be compressed
215 * @return the original object, modified in place
217 public static Object compressLists(Object object) {
218 if (object instanceof Map) {
219 @SuppressWarnings("unchecked")
220 Map<String, Object> asMap = (Map<String, Object>) object;
221 compressMapValues(asMap);
223 } else if (object instanceof List) {
224 @SuppressWarnings("unchecked")
225 List<Object> asList = (List<Object>) object;
226 compressListItems(asList);
229 // else: ignore anything else
235 * Walks a hierarchical map and removes {@code null} items found in any Lists.
237 * @param map map whose lists are to be compressed
239 private static void compressMapValues(Map<String, Object> map) {
240 for (Object value : map.values()) {
241 compressLists(value);
246 * Removes {@code null} items from the list. In addition, it walks the items within
247 * the list, compressing them, as well.
249 * @param list the list to be compressed
251 private static void compressListItems(List<Object> list) {
252 Iterator<Object> iter = list.iterator();
253 while (iter.hasNext()) {
254 Object item = iter.next();
256 // null item - remove it