1 package org.onap.sdc.dcae.catalog.commons;
4 import java.io.IOException;
8 import java.util.HashMap;
9 import java.util.AbstractMap;
10 import java.util.Arrays;
11 import java.util.Iterator;
12 import java.util.Collections;
13 import java.util.Spliterators;
14 import java.util.stream.Stream;
15 import java.util.stream.StreamSupport;
17 import org.apache.commons.jxpath.Pointer;
18 import org.apache.commons.jxpath.JXPathContext;
20 import com.fasterxml.jackson.databind.ObjectMapper;
21 import com.fasterxml.jackson.core.type.TypeReference;
23 import org.onap.sdc.common.onaplog.OnapLoggerDebug;
24 import org.onap.sdc.common.onaplog.Enums.LogLevel;
25 import org.yaml.snakeyaml.Yaml;
29 * Practically a copy of the Validator's service Recycler, minus the Spring framework aspects + picking up the
30 * description of every node
32 public class Recycler {
34 private static final String PROPERTIES = "properties";
35 private static final String VALUE = "value";
36 private static final String ASSIGNMENT = "assignment";
37 private static final String CAPABILITY = "capability";
38 private static final String RELATIONSHIP = "relationship";
39 private static final String NAME = "name";
40 private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
41 private List<Map> imports;
42 private List<String> metas;
49 public Recycler withImports(String... theImports) {
50 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Setting imports to {}", theImports);
51 ListBuilder importsBuilder = new ListBuilder();
52 for (int i = 0; i < theImports.length; i++) {
53 importsBuilder.add(new MapBuilder()
54 .put("i" + i, theImports[i])
57 this.imports = importsBuilder.build();
61 private List imports() {
62 ListBuilder importsBuilder = new ListBuilder();
63 for (Map e: this.imports) {
64 importsBuilder.add(new MapBuilder()
68 return importsBuilder.build();
71 public Recycler withMetas(String... theMetas) {
72 this.metas = (theMetas == null) ? Collections.emptyList() : Arrays.asList(theMetas);
76 public Object recycle(final Reader theSource) throws Exception {
77 return this.recycle(new ObjectMapper().readValue(theSource, (Class)HashMap.class));
80 public Object recycle(final Object theDump) {
82 final JXPathContext jxroot = JXPathContext.newContext(theDump);
83 jxroot.setLenient(true);
85 final Map<String, Object> nodeTemplates =
86 (Map<String, Object>)new MapBuilder()
90 Spliterators.spliteratorUnknownSize((Iterator<Pointer>)jxroot.iteratePointers("/nodes"), 16), false)
92 JXPathContext jxnode = jxroot.getRelativeContext(p);
93 return new AbstractMap.SimpleEntry<String,Object>(
94 (String)jxnode.getValue(NAME) + "_" + (String)jxnode.getValue("nid"),
96 .put("type", jxnode.getValue("type/name"))
97 .put("description", jxnode.getValue("description"))
98 .putOpt("metadata", nodeMetadata(jxnode))
99 .putOpt(PROPERTIES, nodeProperties(jxnode))
100 .putOpt("requirements", nodeRequirements(jxnode))
101 .putOpt("capabilities", nodeCapabilities(jxnode))
106 return new MapBuilder()
107 .put("tosca_definitions_version", "tosca_simple_yaml_1_0_0")
108 .put("imports", imports())
109 .put("topology_template", new MapBuilder()
110 .putOpt("node_templates", nodeTemplates)
116 private Object nodeProperties(JXPathContext theNodeContext) {
120 StreamSupport.stream(
121 Spliterators.spliteratorUnknownSize((Iterator<Map>)theNodeContext.iterate(PROPERTIES), 16), false)
122 .map(m -> new AbstractMap.SimpleEntry(m.get(NAME), this.nodeProperty(m)))
123 .filter(e -> e.getValue() != null)
129 private Object nodeProperty(final Map theSpec) {
130 Object value = theSpec.get(VALUE);
132 value = theSpec.get("default");
134 /*final*/ Map assign = (Map)theSpec.get(ASSIGNMENT);
135 if (assign != null) {
136 value = assign.get(VALUE);
140 String type = (String)theSpec.get("type");
141 if (value != null && type != null) {
142 value = getValueByType(value, type);
147 private Object getValueByType(Object value, String type) {
148 Object returnValue = null;
150 if ("map".equals(type) && !(value instanceof Map)) {
151 returnValue = new ObjectMapper().readValue(value.toString(), new TypeReference<Map>(){});
153 else if ("list".equals(type) && !(value instanceof List)) {
154 returnValue = new ObjectMapper().readValue(value.toString(), new TypeReference<List>(){});
156 else if ("integer".equals(type) && (value instanceof String)) {
157 returnValue = Integer.valueOf((String)value);
159 else if ("float".equals(type) && (value instanceof String)) {
160 returnValue = Double.valueOf((String)value); //double because that's how the yaml parser would encode it
163 catch (NumberFormatException nfx) {
164 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Failed to process String representation {} of numeric data: {}", value, nfx);
166 catch (IOException iox) {
167 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Failed to process {} representation of a collection: {}", value.getClass().getName(), iox);
173 private List nodeRequirements(JXPathContext theNodeContext) {
177 StreamSupport.stream(
178 Spliterators.spliteratorUnknownSize((Iterator<Map>)theNodeContext.iterate("requirements"), 16), false)
179 .flatMap(m -> this.nodeRequirement(m, theNodeContext).stream())
180 //nicer that the ListBuilder buy cannot handle the empty lists, i.e. it will generate empty requirement lists
181 // .collect(Collectors.toList())
187 * @param theSpec the requirement entry that appears within the node specification
188 * @param theNodeContext .. Should I pass the root context instead of assuming that the nodes context has it as parent?
189 * @return a List as one requirement (definition) could end up being instantiated multiple times
191 private List nodeRequirement(final Map theSpec, JXPathContext theNodeContext/*Iterator theTargets*/) {
193 final ListBuilder value = new ListBuilder();
195 final Map target = (Map)theSpec.get("target");
196 final Map capability = (Map)theSpec.get(CAPABILITY);
197 final Map relationship = (Map)theSpec.get(RELATIONSHIP);
199 //this are actual assignments
200 for (Iterator i = theNodeContext.getParentContext().iterate("/relations[@n2='" + theNodeContext.getValue("nid") + "']/meta[@p2='" + theSpec.get(NAME) +"']"); i.hasNext(); ) {
202 String targetNodeName = (String)((Map)i.next()).get("n1");
204 //make sure target exists
205 Map targetNode = (Map)theNodeContext.getParentContext().getValue("/nodes[@nid='" + targetNodeName + "']");
206 if (null == targetNode) {
207 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Relation points to non-existing node {}", targetNodeName);
208 continue; //this risks of producing a partial template ..
211 value.add(new MapBuilder().put(theSpec.get(NAME), new MapBuilder()
212 .putOpt("node", targetNode.get(NAME) + "_" + targetNode.get("nid"))
213 .putOpt(CAPABILITY, capability == null ? null : capability.get(NAME))
214 .putOpt(RELATIONSHIP, relationship == null ? null : relationship.get("type"))
217 addTemporary(theSpec, theNodeContext, value, capability, relationship);
219 if (value.isEmpty()) {
220 value.add(new MapBuilder().put(theSpec.get(NAME), new MapBuilder()
221 .putOpt("node", target == null ? null : target.get(NAME) + "_" + target.get("nid"))
222 .putOpt(CAPABILITY, capability == null ? null : capability.get(NAME))
223 .putOpt(RELATIONSHIP, relationship == null ? null : relationship.get("type"))
227 return value.build();
230 private void addTemporary(Map theSpec, JXPathContext theNodeContext, ListBuilder value, Map capability, Map relationship) {
232 for (Iterator i = theNodeContext.getParentContext().iterate("/relations[@n1='" + theNodeContext.getValue("nid") + "']/meta[@p1='" + theSpec.get(NAME) +"']"); i.hasNext(); ) {
234 String targetNodeName = (String)((Map)i.next()).get("n2");
236 Map targetNode = (Map)theNodeContext.getParentContext().getValue("/nodes[@nid='" + targetNodeName + "']");
237 //make sure target exists
238 if (null == targetNode) {
239 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Relation points to non-existing node {}", targetNode);
240 continue; //this risks of producing a partial template ..
243 value.add(new MapBuilder().put(theSpec.get(NAME), new MapBuilder()
244 .putOpt("node", targetNode.get(NAME) + "_" + targetNode.get("nid"))
245 .putOpt(CAPABILITY, capability == null ? null : capability.get(NAME))
246 .putOpt(RELATIONSHIP, relationship == null ? null : relationship.get("type"))
253 private Map nodeCapabilities(JXPathContext theNodeContext) {
257 StreamSupport.stream(
258 Spliterators.spliteratorUnknownSize((Iterator<Map>)theNodeContext.iterate("capabilities"), 16), false)
259 .map(m -> this.nodeCapability(m))
260 .filter(c -> c != null)
266 * this handles a capability assignment which only includes properties and attributes so unless there
267 * are any properties/attributes assignments we might not generate anything
269 private Map.Entry nodeCapability(final Map theSpec) {
270 List<Map> properties = (List<Map>) theSpec.get(PROPERTIES);
271 if (properties == null || properties.isEmpty()) {
275 return new AbstractMap.SimpleEntry(theSpec.get(NAME),
278 new MapBuilder().putAll(properties.stream()
279 .filter(p -> p.containsKey(ASSIGNMENT) ||
280 p.containsKey(VALUE))
281 .map(p -> new AbstractMap.SimpleEntry(
283 p.containsKey(ASSIGNMENT) ?
284 ((Map) p.get(ASSIGNMENT)).get(VALUE)
294 private Object nodeMetadata(JXPathContext theNodeContext) {
301 Object v = theNodeContext.getValue(m);
303 return Stream.empty();
305 if (v instanceof Map) {
306 return ((Map) v).entrySet()
308 .map(e -> new AbstractMap.SimpleEntry<String, Object>
309 (((Map.Entry) e).getKey().toString(),
310 ((Map.Entry) e).getValue().toString()));
312 return Stream.of(new AbstractMap.SimpleEntry<String,Object>(m, v.toString()));
319 public static String toString(Object theVal) {
320 return new Yaml().dump(theVal);
324 public static void main(String[] theArgs) throws Exception {
325 debugLogger.log(LogLevel.DEBUG, Recycler.class.getName(),
327 new Recycler().recycle(new java.io.FileReader(theArgs[0]))));