1 package org.onap.sdc.dcae.catalog.asdc;
3 import com.google.common.collect.ImmutableMap;
4 import org.apache.commons.io.IOUtils;
5 import org.apache.commons.jxpath.JXPathContext;
6 import org.apache.commons.jxpath.JXPathNotFoundException;
7 import org.apache.commons.lang3.StringUtils;
8 import org.json.JSONArray;
9 import org.json.JSONObject;
10 import org.onap.sdc.common.onaplog.Enums.LogLevel;
11 import org.onap.sdc.common.onaplog.OnapLoggerDebug;
12 import org.onap.sdc.dcae.catalog.Catalog;
13 import org.onap.sdc.dcae.catalog.commons.*;
14 import org.onap.sdc.dcae.checker.*;
18 import java.net.URISyntaxException;
20 import java.util.function.BiFunction;
21 import java.util.stream.Collectors;
22 import java.util.stream.Stream;
23 import java.util.stream.StreamSupport;
25 public class ASDCCatalog implements Catalog {
28 static final String JXPATH_NOT_FOUND_EXCEPTION = "JXPathNotFoundException {}";
30 static final String OCCURRENCES = "occurrences";
32 static final String TOPOLOGY_TEMPLATE_NODE_TEMPLATES = "/topology_template/node_templates";
34 static final String NODES_NAME = "/nodes[name='";
36 static final String ITEM_ID = "itemId";
38 static final String LABELS = "labels";
40 static final String ARTIFACT_URL = "artifactURL";
42 static final String CAPABILITY = "capability";
44 static final String DATABASE = "Database";
46 static final String COLLECTOR = "Collector";
48 static final String MICROSERVICE = "Microservice";
50 static final String ANALYTICS = "Analytics";
52 static final String POLICY = "Policy";
54 static final String SOURCE = "Source";
56 static final String UTILITY = "Utility";
58 static final String NAME = "name";
60 static final String ID = "id";
62 static final String ARTIFACT_NAME = "artifactName";
64 static final String DESCRIPTION = "description";
66 static final String MODELS = "models";
68 static final String ARTIFACTS = "artifacts";
70 static final String ITEMS = "items";
72 static final String PROPERTIES = "']/properties";
74 static final String TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 = "/topology_template/node_templates/";
76 static final String PROPERTIES_NAME = "']/properties[name='";
78 static final String CAPABILITIES = "']/capabilities";
80 static final String CAPABILITIES_NAME = "']/capabilities[name='";
82 private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
86 private JSONObject folders = new JSONObject();
87 private String[] folderFields = new String[] {ID, ITEM_ID, NAME};
89 private ProxyBuilder proxies;
90 private Map<Target, JXPathContext> contexts = new HashMap<Target, JXPathContext>();
92 // resource and its catalog
93 private Map<UUID, org.onap.sdc.dcae.checker.Catalog> catalogs = new HashMap<UUID, org.onap.sdc.dcae.checker.Catalog>();
95 public ASDCCatalog(URI theURI) {
97 this.asdc = new ASDC();
98 this.asdc.setUri(theURI);
102 this.proxies = new ProxyBuilder().withConverter(v -> v == null ? null : UUID.fromString(v.toString()), UUID.class)
104 new ImmutableMap.Builder<String, BiFunction<Proxy, Object[], Object>>().put("data", (proxy, args) -> proxy.data())
105 .build()).withContext(new ImmutableMap.Builder<String, Object>().put("catalog", this).build());
108 private void initFolders() {
110 JSONArray labels = new JSONArray();
111 labels.put("Folder");
113 labels.put("Superportfolio"); // for CCD compatibility
115 folders.put(DATABASE, new JSONObject().put(NAME, DATABASE).put(ID, "dcae_database")
116 .put(ITEM_ID, DATABASE).put(LABELS, labels));
117 folders.put(COLLECTOR, new JSONObject().put(NAME, COLLECTOR).put(ID, "dcae_collector")
118 .put(ITEM_ID, COLLECTOR).put(LABELS, labels));
119 folders.put(MICROSERVICE, new JSONObject().put(NAME, MICROSERVICE).put(ID, "dcae_microservice")
120 .put(ITEM_ID, MICROSERVICE).put(LABELS, labels));
121 folders.put(ANALYTICS, new JSONObject().put(NAME, ANALYTICS).put(ID, "dcae_analytics")
122 .put(ITEM_ID, ANALYTICS).put(LABELS, labels));
123 folders.put(POLICY, new JSONObject().put(NAME, POLICY).put(ID, "dcae_policy").put(ITEM_ID, POLICY)
124 .put(LABELS, labels));
125 folders.put(SOURCE, new JSONObject().put(NAME, SOURCE).put(ID, "dcae_source").put(ITEM_ID, SOURCE)
126 .put(LABELS, labels));
127 folders.put(UTILITY, new JSONObject().put(NAME, UTILITY).put(ID, "dcae_utility")
128 .put(ITEM_ID, UTILITY).put(LABELS, labels));
131 public URI getUri() {
132 return this.asdc.getUri();
135 public String namespace() {
139 public boolean same(Catalog theCatalog) {
143 public <T> T proxy(JSONObject theData, Class<T> theType) {
144 return proxies.build(theData, theType);
148 public Future<Folders> roots() {
150 Folders roots = new Folders();
151 for (Iterator fi = folders.keys(); fi.hasNext();) {
152 roots.add(proxies.build(folders.getJSONObject((String) fi.next()), Folder.class));
154 return Futures.succeededFuture(roots);
158 public Future<Folders> rootsByLabel(String theLabel) {
160 Folders roots = new Folders();
161 for (Iterator fi = folders.keys(); fi.hasNext();) {
162 JSONObject folder = folders.getJSONObject((String) fi.next());
163 JSONArray labels = folder.getJSONArray(LABELS);
165 for (int i = 0; i < labels.length(); i++) {
166 if (labels.get(i).equals(theLabel)) {
167 roots.add(proxies.build(folder, Folder.class));
171 return Futures.succeededFuture(roots);
175 public Future<Mixels> lookup(JSONObject theSelector) {
176 return Futures.succeededFuture(new Mixels());
179 public Future<Mixels> lookup(String theAnnotation, JSONObject theSelector) {
180 return Futures.succeededFuture(new Mixels());
184 public ItemAction item(String theItemId) {
185 return new ResourceAction(UUID.fromString(theItemId));
189 public FolderAction folder(String theFolderId) {
190 return new FolderAction(theFolderId);
193 public TemplateAction template(String theId) {
194 return new TemplateAction(theId);
197 public TypeAction type(String theItemId, String theName) {
198 return new TypeAction(UUID.fromString(theItemId), theName);
201 protected static String resolveTargetName(Target theTarget) {
202 return (String) ((Map) ((Map) theTarget.getTarget()).get("metadata")).get("template_name");
205 protected Object resolve(Target theTarget, String thePath) {
207 return contexts.get(theTarget).getValue(thePath);
208 } catch (JXPathNotFoundException pnfx) {
209 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "JXPathNotFoundException {}", pnfx);
214 // covers common TOSCA pattern of single entry maps
215 public Map.Entry<String, Map> toEntry(Object theValue) {
216 return (Map.Entry<String, Map>) ((Map) theValue).entrySet().iterator().next();
219 protected Map selectEntries(Map theOriginal, String... theKeys) {
220 Arrays.sort(theKeys);
221 Map selection = ((Set<Map.Entry>) theOriginal.entrySet()).stream()
222 .filter(e -> Arrays.binarySearch(theKeys, e.getKey().toString()) >= 0)
223 .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
227 protected Map evictEntries(Map theOriginal, String... theKeys) {
228 Arrays.sort(theKeys);
229 Map selection = ((Set<Map.Entry>) theOriginal.entrySet()).stream()
230 .filter(e -> Arrays.binarySearch(theKeys, e.getKey().toString()) < 0)
231 .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
235 protected MapBuilder renderEntry(Map.Entry theEntry, String... theKeys) {
236 MapBuilder out = new MapBuilder();
237 out.put(NAME, theEntry.getKey());
239 for (String key : theKeys) {
240 out.put(key, ((Map) theEntry.getValue()).get(key));
245 protected <T> Stream<T> stream(Iterator<T> theSource) {
246 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(theSource,
247 Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.IMMUTABLE), false);
250 private JSONArray selectModels(JSONArray theArtifacts) {
251 JSONArray models = new JSONArray();
252 if (theArtifacts == null) {
256 for (int i = 0; i < theArtifacts.length(); i++) {
257 JSONObject artifact = theArtifacts.getJSONObject(i);
258 String name = artifact.optString(ARTIFACT_NAME);
259 if (name != null && StringUtils.containsIgnoreCase(name, "template")) {
260 models.put(new JSONObject().putOpt(NAME, artifact.optString(ARTIFACT_NAME))
261 .putOpt("version", artifact.optString("artifactVersion"))
262 .putOpt(DESCRIPTION, artifact.optString("artifactType"))
263 .putOpt(ID, artifact.optString(ARTIFACT_URL))
264 .putOpt(ITEM_ID, artifact.optString(ARTIFACT_URL)));
270 private JSONObject patchResource(JSONObject theResource) {
272 theResource.remove("resources");
273 theResource.putOpt(ID, theResource.opt("uuid"));
274 theResource.putOpt(ITEM_ID, theResource.opt("uuid"));
279 private static void dumpTargets(String theDirName, Collection<Target> theTargets) {
281 File targetDir = new File(theDirName);
282 if (!targetDir.exists() && !targetDir.mkdirs()) {
283 throw new IllegalStateException("Couldn't create dir: " + theDirName);
285 for (Target t : theTargets) {
286 FileWriter dump = new FileWriter(new File(theDirName, t.getName()));
287 IOUtils.copy(t.open(), dump);
290 } catch (IOException iox) {
291 debugLogger.log(LogLevel.DEBUG,"ASDCCatalog", "IOException {}", iox);
295 private static URI asURI(String theValue) {
297 return new URI(theValue);
298 } catch (URISyntaxException urisx) {
299 throw new IllegalArgumentException("Invalid URI", urisx);
303 private static UUID asUUID(String theValue) {
304 return UUID.fromString(theValue);
307 private org.onap.sdc.dcae.checker.Catalog getCatalog(UUID theResourceId) {
308 return this.catalogs.get(theResourceId);
311 private String getArtifactVersion(JSONObject theData) {
312 return theData.getString("artifactVersion");
315 private String getArtifactName(JSONObject theData) {
316 return theData.getString(ARTIFACT_NAME);
319 private String getArtifactURL(JSONObject theData) {
320 return theData.getString(ARTIFACT_URL);
323 private URI getArtifactURI(JSONObject theData) {
324 return asURI(theData.getString(ARTIFACT_URL));
328 public class ResourceAction implements Catalog.ItemAction<Resource> {
331 private boolean doModels;
333 ResourceAction(UUID theItemId) {
334 this.iid = theItemId;
337 public ResourceAction withModels() {
338 this.doModels = true;
342 public ResourceAction withAnnotations() {
347 public Future<Resource> execute() {
349 return Futures.advance(asdc.getResource(this.iid, JSONObject.class), resourceData -> {
351 resourceData.put(MODELS, selectModels(resourceData.optJSONArray(ARTIFACTS)));
353 return proxies.build(patchResource(resourceData), Resource.class);
357 protected Future<JSONObject> executeRaw() {
359 return Futures.advance(asdc.getResource(this.iid, JSONObject.class), resourceData -> {
361 resourceData.put(MODELS, selectModels(resourceData.optJSONArray(ARTIFACTS)));
364 }, resourceError -> new RuntimeException("Failed to retrieve item " + this.iid, resourceError));
368 public class FolderAction implements Catalog.FolderAction {
370 private boolean doItemModels;
371 private String folderName;
373 // use the id/UUID of the folder ??
374 private FolderAction(String theFolderName) {
375 this.folderName = theFolderName;
378 public FolderAction withAnnotations() {
382 public FolderAction withAnnotations(String theSelector) {
386 public FolderAction withItems() {
390 public FolderAction withItemAnnotations() {
394 public FolderAction withItemAnnotations(String theSelector) {
398 public FolderAction withItemModels() {
403 public FolderAction withParts() {
407 public FolderAction withPartAnnotations() {
411 public FolderAction withPartAnnotations(String theSelector) {
416 public Future<Folder> execute() {
418 JSONObject folder = folders.optJSONObject(this.folderName);
419 if (folder == null) {
420 return Futures.failedFuture(new RuntimeException("No such folder " + this.folderName));
423 final JSONObject folderView = new JSONObject(folder, folderFields);
425 return Futures.advance(asdc.getResources(JSONArray.class, "DCAE Component", this.folderName),
428 Actions.CompoundAction<Resource> itemsAction = new Actions.BasicCompoundAction<Resource>();
429 for (int i = 0; i < resourcesData.length(); i++) {
430 JSONObject resource = resourcesData.getJSONObject(i);
434 .addAction(new ResourceAction(asUUID(resource.getString("uuid"))).withModels());
436 folderView.append(ITEMS, patchResource(resource));
441 List<Resource> items = itemsAction.execute().waitForResult();
442 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Number of DCAE item for : {} is {}", this.folderName, items.size());
444 for (Resource res : filterLatestVersion(items)) {
445 folderView.append(ITEMS, patchResource(res.data()));
447 } catch (Exception x) {
448 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Exception {}", x);
449 throw new RuntimeException("Failed to retrieve folder items", x);
452 return proxies.build(folderView, Folder.class);
453 }, resourcesError -> new RuntimeException("Failed to retrieve resources", resourcesError));
456 public Collection<Resource> filterLatestVersion(Collection<Resource> items) throws IllegalArgumentException {
458 throw new IllegalArgumentException("null is not acceptable as a list of items");
460 Map<UUID, Resource> itemsMap = new HashMap<UUID, Resource>(items.size());
461 for (Resource r : items) {
462 if (itemsMap.containsKey(r.invariantUUID()) && isNewerVersion(itemsMap, r)) {
463 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Avoiding adding item {} since it has a advanced version already", r.toString());
466 itemsMap.put(r.invariantUUID(), r);
468 return itemsMap.values();
471 private boolean isNewerVersion(Map<UUID, Resource> itemsMap, Resource r) {
472 return Float.valueOf(itemsMap.get(r.invariantUUID()).version()) > Float.valueOf(r.version());
478 public class TemplateAction implements Catalog.TemplateAction {
480 private String artifactId;
481 private Target target;
482 private org.onap.sdc.dcae.checker.Catalog catalog;
483 private JXPathContext ctx = JXPathContext.newContext(new HashMap());
485 private boolean doNodes, doNodeProperties, doNodePropertiesAssignments, doNodeRequirements, doNodeCapabilities,
486 doNodeCapabilityProperties, doNodeCapabilityPropertyAssignments;
488 protected TemplateAction(Target theTarget) {
489 this.target = theTarget;
493 * expected to be the relative url provided by asdc for the template
496 protected TemplateAction(String theArtifactId) {
497 this.artifactId = theArtifactId;
500 public TemplateAction withInputs() {
504 public TemplateAction withOutputs() {
508 public TemplateAction withNodes() {
513 protected TemplateAction doNodes() {
518 Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
523 ctx.setValue("/nodes",
524 nodes.entrySet().stream()
525 .map(nodeEntry -> new MapBuilder().put(NAME, ((Map.Entry) nodeEntry).getKey())
526 .put(DESCRIPTION, this.artifactId)
527 .putAll(selectEntries((Map) ((Map.Entry) nodeEntry).getValue(), "type")).build())
528 .collect(Collectors.toList()));
533 // pre-requisite: a call to 'withNodes'
534 public TemplateAction withNodeProperties() {
535 this.doNodeProperties = true;
539 protected TemplateAction doNodeProperties() {
540 if (!this.doNodeProperties) {
544 Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
549 nodes.entrySet().stream().forEach(node -> ctx.setValue(
550 NODES_NAME + ((Map.Entry) node).getKey() + PROPERTIES,
551 stream(catalog.facets(Construct.Node, Facet.properties,
552 ((Map) ((Map.Entry) node).getValue()).get("type").toString()))
553 .map(propEntry -> new MapBuilder().put(NAME, propEntry.getKey())
554 .putAll((Map) propEntry.getValue()).build())
555 .collect(Collectors.toList())));
560 // pre-requisite: a call to 'withNodesProperties'
561 public TemplateAction withNodePropertiesAssignments() {
562 this.doNodePropertiesAssignments = true;
566 protected TemplateAction doNodePropertiesAssignments() {
567 if (!this.doNodePropertiesAssignments) {
571 Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
576 nodes.entrySet().stream().forEach(node -> {
577 List nodeProps = null;
579 nodeProps = (List) ctx.getValue(NODES_NAME + ((Map.Entry) node).getKey() + PROPERTIES);
580 } catch (JXPathNotFoundException pnfx) {
581 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
585 nodeProps.stream().forEach(prop -> {
587 String propPath = TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 + ((Map.Entry) node).getKey()
588 + "/properties/" + ((Map) prop).get(NAME);
589 Object propValue = resolve(this.target, propPath);
590 // to conform with the db based api we should analyze the
591 // value for function calls
593 propPath = NODES_NAME + ((Map.Entry) node).getKey() + PROPERTIES_NAME
594 + ((Map) prop).get(NAME) + "']";
595 if (propValue != null) {
596 ctx.setValue(propPath + "/assignment",
597 new ImmutableMap.Builder().put("value", propValue).build());
605 protected Map renderRequirementDefinition(Map.Entry theReq) {
606 Map def = (Map) theReq.getValue();
607 return new MapBuilder().put(NAME, theReq.getKey())
608 // capability must be present
610 new MapBuilder().put(NAME, def.get(CAPABILITY))
611 .put(ID, this.target.getName() + "/" + def.get(CAPABILITY)).build())
612 .putAll(evictEntries(def, CAPABILITY)).build();
615 // TODO: see how this comes out of neo and match it
616 protected Map renderRequirementAssignment(Map.Entry theReq) {
617 Map def = (Map) theReq.getValue();
618 return new MapBuilder().put(NAME, theReq.getKey())
619 // capability must be present
621 new MapBuilder().put(NAME, def.get(CAPABILITY))
622 // we provide an id only if the capability
625 catalog.hasType(Construct.Capability, (String) def.get(CAPABILITY))
626 ? (this.target.getName() + "/" + def.get(CAPABILITY)) : null)
628 .putAll(evictEntries(def, CAPABILITY)).build();
631 public TemplateAction withNodeRequirements() {
632 this.doNodeRequirements = true;
636 TemplateAction doNodeRequirements() {
637 if (!this.doNodeRequirements) {
641 // requirements come first from the type and then can be further
642 // refined by their assignment within the
644 Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
650 nodes.entrySet().stream()
659 .stream(Spliterators.spliteratorUnknownSize(
660 catalog.requirements(((Map) ((Map.Entry) node).getValue())
661 .get("type").toString()),
662 Spliterator.NONNULL | Spliterator.DISTINCT
663 | Spliterator.IMMUTABLE),
665 .map((Map.Entry reqEntry) -> renderRequirementDefinition(reqEntry))
666 .collect(Collectors.toList())));
668 // merge assignments on top of definitions
669 nodes.entrySet().stream().forEach(node -> {
670 List nodeReqsAssigns = (List) resolve(this.target,
671 TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 + ((Map.Entry) node).getKey() + "/requirements");
672 if (nodeReqsAssigns == null) {
675 nodeReqsAssigns.stream().forEach(req -> {
676 Map.Entry reqAssign = toEntry(req);
677 catalog.mergeDefinitions((Map) ctx.getValue(NODES_NAME + ((Map.Entry) node).getKey()
678 + "']/requirements[name='" + reqAssign.getKey() + "']"),
679 renderRequirementAssignment(reqAssign));
686 public TemplateAction withNodeCapabilities() {
687 this.doNodeCapabilities = true;
691 protected Map renderCapabilityDefinition(Map.Entry theCap) {
692 Map def = (Map) theCap.getValue();
693 return new MapBuilder().put(NAME, theCap.getKey())
695 new MapBuilder().put(NAME, def.get("type"))
696 .put(ID, this.target.getName() + "/" + def.get("type")).build())
697 .putAll(evictEntries(def, "properties", "type")).build();
700 TemplateAction doNodeCapabilities() {
701 if (!this.doNodeCapabilities) {
705 Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
710 // collect capabilities through the node type hierarchy
712 // we evict the properties from the node type capability declaration
713 // (when declaring a capability with the
714 // node type some re-definition of capability properties can take
716 nodes.entrySet().stream()
717 .forEach(node -> ctx.setValue(NODES_NAME + ((Map.Entry) node).getKey() + CAPABILITIES,
719 stream(catalog.facets(Construct.Node, Facet.capabilities,
720 ((Map) ((Map.Entry) node).getValue()).get("type").toString()))
721 .map((Map.Entry capEntry) -> renderCapabilityDefinition(capEntry))
722 .collect(Collectors.toList())));
727 public TemplateAction withNodeCapabilityProperties() {
728 this.doNodeCapabilityProperties = true;
732 TemplateAction doNodeCapabilityProperties() {
734 if (!this.doNodeCapabilityProperties) {
738 Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
743 // pick up all the properties from the capability type hierarchy
745 nodes.entrySet().stream().forEach(node -> {
746 List nodeCapabilities = (List) ctx
747 .getValue(NODES_NAME + ((Map.Entry) node).getKey() + CAPABILITIES);
748 if (nodeCapabilities == null) {
752 // collect properties from the capability type hierarchy
753 nodeCapabilities.stream().forEach(capability -> {
754 List capabilityProperties = StreamSupport
755 .stream(Spliterators.spliteratorUnknownSize(
756 catalog.facets(Construct.Capability, Facet.properties,
757 ((Map)((Map)capability).get("type")).get(NAME).toString()),
758 Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.IMMUTABLE), false)
759 .map((Map.Entry capEntry) -> new MapBuilder().put(NAME, capEntry.getKey())
760 .putAll((Map) capEntry.getValue()).build())
761 .collect(Collectors.toList());
763 if (!capabilityProperties.isEmpty()) {
764 ctx.setValue(NODES_NAME + ((Map.Entry) node).getKey() + CAPABILITIES_NAME
765 + ((Map) capability).get(NAME) + PROPERTIES, capabilityProperties);
769 // and go over the node type (hierarchy) and pick up any
770 // re-definitions from there.
772 .stream(Spliterators.spliteratorUnknownSize(
773 catalog.facets(Construct.Node, Facet.capabilities,
774 ((Map) ((Map.Entry) node).getValue()).get("type").toString()),
775 Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.IMMUTABLE), false)
776 .forEach((Map.Entry capability) -> {
777 // for each capability property that has some node
778 // type level re-definition
779 Map properties = (Map) ((Map) capability.getValue()).get("properties");
780 if (properties == null) {
784 properties.entrySet().stream().forEach(property -> {
785 String propertyLoc = NODES_NAME + ((Map.Entry) node).getKey()
786 + CAPABILITIES_NAME + ((Map) capability).get(NAME)
787 + PROPERTIES_NAME + ((Map.Entry) property).getKey() + "']";
788 ctx.setValue(propertyLoc, catalog.mergeDefinitions((Map) ctx.getValue(propertyLoc),
789 (Map) ((Map.Entry) property).getValue()));
797 public TemplateAction withNodeCapabilityPropertyAssignments() {
798 this.doNodeCapabilityPropertyAssignments = true;
802 TemplateAction doNodeCapabilityPropertyAssignments() {
803 if (!this.doNodeCapabilityPropertyAssignments) {
807 // this is a wasteful: we go over all declared
808 // nodes/capabilities/properties and check if there is an assigned
809 // value in the actual template. It is optimal to approach the
810 // problem from the other direction: go over delared
811 // assignments and set them in the output structure ..
815 nodes = (List) ctx.getValue("/nodes");
816 } catch (JXPathNotFoundException pnfx) {
817 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
821 nodes.stream().forEach(node -> {
822 List capabilities = (List) ctx.getValue(NODES_NAME + ((Map) node).get(NAME) + CAPABILITIES);
823 if (capabilities == null) {
827 capabilities.stream().forEach(capability -> {
828 List properties = null;
830 properties = (List) ctx.getValue(NODES_NAME + ((Map) node).get(NAME)
831 + CAPABILITIES_NAME + ((Map) capability).get(NAME) + PROPERTIES);
832 } catch (JXPathNotFoundException pnfx) {
833 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
837 properties.stream().forEach(property -> {
838 String location = NODES_NAME + ((Map) node).get(NAME) + CAPABILITIES_NAME
839 + ((Map) capability).get(NAME) + PROPERTIES_NAME + ((Map) property).get(NAME)
842 // pick the value from the original
844 Object assignment = resolve(this.target,
845 TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 + ((Map) node).get(NAME) + "/capabilities/"
846 + ((Map) capability).get(NAME) + "/properties/"
847 + ((Map) property).get(NAME));
848 if (assignment != null) {
849 ctx.setValue(location, new ImmutableMap.Builder().put("value", assignment).build());
851 } catch (JXPathNotFoundException pnfx) {
852 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
853 // it's ok, no assignment
862 public TemplateAction withPolicies() {
866 public TemplateAction withPolicyProperties() {
870 public TemplateAction withPolicyPropertiesAssignments() {
874 public Future<Template> execute() {
876 if (this.target == null) {
878 String[] parts = this.artifactId.split("/");
879 if (parts.length != 8) {
881 .failedFuture(new Exception("Unexpected artifact id for template " + this.artifactId));
884 UUID resourceId = asUUID(parts[5]);
885 this.catalog = ASDCCatalog.this.catalogs.get(resourceId);
887 // if we find a catalog for this resource we have to figure out
888 // if it contains the required target ..
891 JSONObject resource = new ResourceAction(resourceId).executeRaw().waitForResult();
893 Checker checker = new Checker();
894 TargetLocator locator = new ASDCLocator(resource.getJSONArray(ARTIFACTS),
895 ASDCCatalog.this.catalogs.get(resourceId));
896 checker.setTargetLocator(locator);
898 Target template = locator.resolve("template");
899 if (template == null) {
900 return Futures.failedFuture(new Exception("Failed to locate template in " + resource));
903 checker.check(template);
905 for (Target t : checker.targets()) {
906 if (t.getReport().hasErrors()) {
907 dumpTargets(resourceId.toString(), checker.targets());
908 return Futures.failedFuture(new Exception("Failed template validation: " + t.getReport()));
912 this.target = template;
913 this.catalog = checker.catalog();
914 ASDCCatalog.this.catalogs.put(resourceId, this.catalog);
915 // we should only be doing this if we discovered an update
916 // (by checking timestampts). Actually, we should
917 // only do the artifact fetching if we detect an update
918 ASDCCatalog.this.contexts.put(template, JXPathContext.newContext(template.getTarget()));
919 } catch (Exception x) {
920 return Futures.failedFuture(x);
924 this.doNodes().doNodeProperties().doNodePropertiesAssignments().doNodeRequirements().doNodeCapabilities()
925 .doNodeCapabilityProperties().doNodeCapabilityPropertyAssignments();
927 JSONObject pack = new JSONObject((Map) ctx.getContextBean()).put(NAME, this.target.getName().toString())
928 .put(ID, this.target.getLocation().toString())
929 .put(ITEM_ID, this.target.getLocation().toString());
930 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), pack.toString(2));
932 return Futures.succeededFuture(proxies.build(pack, Template.class));
936 public class TypeAction implements Catalog.TypeAction {
939 private UUID resourceId;
940 private JXPathContext ctx;
942 private boolean doHierarchy = false, doRequirements = false, doCapabilities = false;
944 private TypeAction(UUID theResourceId, /* Construct theConstruct, */ String theName) {
945 this.resourceId = theResourceId;
949 public TypeAction withHierarchy() {
950 this.doHierarchy = true;
954 TypeAction doHierarchy(org.onap.sdc.dcae.checker.Catalog theCatalog) {
955 if (!this.doHierarchy) {
959 ctx.setValue("/hierarchy",
960 stream(theCatalog.hierarchy(Construct.Node, this.name)).skip(1) // skip
962 .map((Map.Entry type) -> new MapBuilder()
963 .put(NAME, type.getKey()).put(ID, resourceId + "/" + type.getKey())
964 .putOpt(DESCRIPTION, ((Map) type.getValue()).get(DESCRIPTION)).build())
965 // renderEntry((Map.Entry)type,
966 // "description").build())
967 .collect(Collectors.toList()));
971 public TypeAction withRequirements() {
972 this.doRequirements = true;
976 TypeAction doRequirements(org.onap.sdc.dcae.checker.Catalog theCatalog) {
977 if (!this.doRequirements) {
981 ctx.setValue("requirements", stream(theCatalog.requirements(this.name)).map((Map.Entry req) -> {
982 String capability = (String) ((Map) req.getValue()).get(CAPABILITY),
983 node = (String) ((Map) req.getValue()).get(CAPABILITY);
984 return new MapBuilder().put(NAME, req.getKey()).put(ID, resourceId + "/" + req.getKey())
985 .put(OCCURRENCES, ((Map) req.getValue()).get(OCCURRENCES))
987 new MapBuilder().put(NAME, capability)
988 // if the capability points to a
989 // capability type then encode
990 // the type reference, else it is a name
991 // (within a node type)
993 getCatalog(resourceId).hasType(Construct.Capability, capability)
994 ? (resourceId + "/" + capability) : capability.toString())
996 .put("node", new MapBuilder().putOpt(NAME, node).putOpt(ID, node == null ? null
997 : (resourceId + "/" + node)).buildOpt())
998 .put("relationship", ((Map) req.getValue()).get("relationship"))
999 // renderEntry((Map.Entry)requirement, "occurrences",
1000 // "node", "capability", "relationship")
1002 }).collect(Collectors.toList()));
1007 public TypeAction withCapabilities() {
1008 this.doCapabilities = true;
1012 TypeAction doCapabilities(org.onap.sdc.dcae.checker.Catalog theCatalog) {
1013 if (!this.doCapabilities) {
1017 ctx.setValue("capabilities",
1019 .facets(Construct.Node, Facet.capabilities,
1021 .map((Map.Entry capability) -> new MapBuilder()
1022 .put(NAME, capability.getKey()).put("type",
1024 .put(NAME, ((Map) capability.getValue())
1028 + ((Map) capability.getValue())
1032 ((Map) capability.getValue()).get(OCCURRENCES))
1033 .putOpt("validSourceTypes",
1034 ((Map) capability.getValue()).get("validSourceTypes"))
1036 // renderEntry((Map.Entry)capability,
1038 // "validSourceTypes")
1039 ).collect(Collectors.toList()));
1043 public Future<Type> execute() {
1044 org.onap.sdc.dcae.checker.Catalog catalog = ASDCCatalog.this.catalogs.get(this.resourceId);
1045 if (catalog == null) {
1046 return Futures.failedFuture(new Exception("No catalog available for resource " + this.resourceId
1047 + ". You might want to fetch the model first."));
1050 if (!catalog.hasType(Construct.Node, this.name)) {
1051 return Futures.failedFuture(
1052 new Exception("No " + this.name + " type in catalog for resource " + this.resourceId));
1055 this.ctx = JXPathContext
1056 .newContext(new MapBuilder().put(NAME, this.name).put(ID, this.resourceId + "/" + this.name)
1057 .put(ITEM_ID, this.resourceId + "/" + this.name).build());
1059 this.doHierarchy(catalog).doRequirements(catalog).doCapabilities(catalog);
1061 JSONObject pack = new JSONObject((Map) this.ctx.getContextBean());
1062 debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), pack.toString(2));
1064 return Futures.succeededFuture(proxies.build((Map) ctx.getContextBean(), Type.class));
1068 public static interface Resource extends Catalog.Item<Resource> {
1071 @Proxy.DataMap(map = "uuid")
1076 public UUID invariantUUID();
1078 public String category();
1080 public String subCategory();
1082 public String lastUpdaterFullName();
1084 public String version();
1086 @Proxy.DataMap(proxy = true, elementType = Artifact.class)
1087 public Artifacts artifacts();
1091 public static class Resources extends Elements<Resource> {
1094 public static interface Artifact extends Catalog.Element<Artifact> {
1096 @Proxy.DataMap(map = ARTIFACT_NAME)
1097 public String name();
1099 @Proxy.DataMap(map = "artifactType")
1100 public String type();
1102 @Proxy.DataMap(map = "artifactDescription")
1103 public String description();
1105 @Proxy.DataMap(map = "artifactUUID")
1108 @Proxy.DataMap(map = "artifactVersion")
1109 public int version();
1113 public static class Artifacts extends Elements<Artifact> {
1116 public class ASDCLocator implements TargetLocator {
1118 private JSONArray artifacts;
1119 private org.onap.sdc.dcae.checker.Catalog catalog;
1121 private ASDCLocator(JSONArray theArtifacts, org.onap.sdc.dcae.checker.Catalog theCatalog) {
1122 this.artifacts = theArtifacts;
1123 this.catalog = theCatalog;
1126 public boolean addSearchPath(URI theURI) {
1130 public boolean addSearchPath(String thePath) {
1134 public Iterable<URI> searchPaths() {
1135 return Collections.emptySet();
1138 public Target resolve(String theName) {
1139 JSONObject targetArtifact = null;
1141 for (int i = 0; i < this.artifacts.length(); i++) {
1142 JSONObject artifact = this.artifacts.getJSONObject(i);
1143 String artifactName = artifact.getString(ARTIFACT_NAME);
1144 if (StringUtils.containsIgnoreCase(artifactName, theName)) {
1145 targetArtifact = artifact;
1149 if (targetArtifact == null) {
1153 ASDCTarget target = null;
1154 if (this.catalog != null) {
1155 // this is the caching!!
1156 target = (ASDCTarget) this.catalog.getTarget(ASDCCatalog.this.getArtifactURI(targetArtifact));
1157 if (target != null && target.getVersion().equals(ASDCCatalog.this.getArtifactVersion(targetArtifact))) {
1162 return new ASDCTarget(targetArtifact);
1166 public class ASDCTarget extends Target {
1168 private String content;
1169 private JSONObject artifact;
1171 private ASDCTarget(JSONObject theArtifact) {
1172 super(ASDCCatalog.this.getArtifactName(theArtifact), ASDCCatalog.this.getArtifactURI(theArtifact));
1173 this.artifact = theArtifact;
1176 // here is a chance for caching within the catalog! Do not go fetch the
1177 // artifact if it has not been changed since the
1181 public Reader open() throws IOException {
1182 if (this.content == null) {
1184 this.content = ASDCCatalog.this.asdc
1185 .fetch(ASDCCatalog.this.getArtifactURL(this.artifact), String.class).waitForResult();
1186 } catch (Exception x) {
1187 throw new IOException("Failed to load " + ASDCCatalog.this.getArtifactURL(this.artifact), x);
1191 // should return immediately a reader blocked until content
1192 // available .. hard to handle errors
1193 return new StringReader(this.content);
1196 public String getVersion() {
1197 return ASDCCatalog.this.getArtifactVersion(this.artifact);
1202 public static void main(String[] theArgs) throws Exception {
1204 ASDCCatalog catalog = new ASDCCatalog(new URI(theArgs[0]));
1206 Folder f = catalog.folder(theArgs[1]).withItems().withItemModels().execute().waitForResult();
1208 debugLogger.log(LogLevel.DEBUG, ASDCCatalog.class.getName(), "folder: {}", f.data());
1210 Resources items = f.elements(ITEMS, Resources.class);
1211 if (items != null) {
1212 for (Resource item : items) {
1213 debugLogger.log(LogLevel.DEBUG, ASDCCatalog.class.getName(), "\titem: {} : {}",item.name(), item.data());
1214 Templates templates = item.elements(MODELS, Templates.class);
1215 if (templates != null) {
1216 for (Template t : templates) {
1217 Template ft = catalog.template(t.id()).withNodes().withNodeProperties()
1218 .withNodePropertiesAssignments().execute().waitForResult();
1220 debugLogger.log(LogLevel.DEBUG, ASDCCatalog.class.getName(), "template data: {}", ft.data());