summaryrefslogtreecommitdiffstats
path: root/dcaedt_catalog/api
diff options
context:
space:
mode:
Diffstat (limited to 'dcaedt_catalog/api')
-rw-r--r--dcaedt_catalog/api/pom.xml198
-rw-r--r--dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/Catalog.java440
-rw-r--r--dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCCatalog.java1227
-rw-r--r--dcaedt_catalog/api/src/main/resources/log4j.properties8
-rw-r--r--dcaedt_catalog/api/src/test/java/org/onap/sdc/dcae/catalog/ASDCCatalogTest.java88
5 files changed, 1961 insertions, 0 deletions
diff --git a/dcaedt_catalog/api/pom.xml b/dcaedt_catalog/api/pom.xml
new file mode 100644
index 0000000..234f12f
--- /dev/null
+++ b/dcaedt_catalog/api/pom.xml
@@ -0,0 +1,198 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.sdc.dcae</groupId>
+ <artifactId>DCAE-DT-Catalog</artifactId>
+ <version>1806.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>DCAE-DT-Catalog-API</artifactId>
+ <packaging>jar</packaging>
+ <name>DCAE DT Catalog API</name>
+
+ <build>
+ <sourceDirectory>src/main/java</sourceDirectory>
+ <testSourceDirectory>src/test/java</testSourceDirectory>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ <encoding>${project.build.sourceEncoding}</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/deps</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>buildnumber-maven-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <phase>validate</phase>
+ <goals>
+ <goal>create</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <doCheck>false</doCheck>
+ <doUpdate>false</doUpdate>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.1</version>
+ <configuration>
+ <archive>
+ <manifest>
+ <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+ </manifest>
+ <manifestEntries>
+ <Implementation-Build>${buildNumber}</Implementation-Build>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.0.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ <archive>
+ <manifest>
+ <mainClass>org.onap.sdc.dcae.catalog.test.Cataloged</mainClass>
+ </manifest>
+ <manifestEntries>
+ <Implementation-Build>${buildNumber}</Implementation-Build>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ <!-- <executions> <execution> <id>make-assembly</id> this is used for
+ inheritance merges <phase>package</phase> bind to the packaging phase <goals>
+ <goal>single</goal> </goals> </execution> </executions> -->
+ </plugin>
+ </plugins>
+ </build>
+ <repositories>
+ <repository>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ <id>jcenter</id>
+ <name>Bintray JCenter</name>
+ <url>http://repo1.maven.org/maven2/</url>
+ </repository>
+ </repositories>
+ <dependencies>
+ <dependency>
+ <groupId>commons-jxpath</groupId>
+ <artifactId>commons-jxpath</artifactId>
+ <version>1.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpasyncclient</artifactId>
+ <version>4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20160810</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onap.sdc.dcae</groupId>
+ <artifactId>DCAE-DT-Catalog-Commons</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.sdc.dcae</groupId>
+ <artifactId>DCAE-DT-Catalog-ASDC</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onap.sdc.dcae</groupId>
+ <artifactId>DCAE-DT-Validator-Checker</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>1.10.19</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <!-- use 2.8.0 for Java 7 projects -->
+ <version>3.8.0</version>
+ <scope>test</scope>
+ </dependency>
+
+
+ </dependencies>
+</project>
diff --git a/dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/Catalog.java b/dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/Catalog.java
new file mode 100644
index 0000000..b73bb09
--- /dev/null
+++ b/dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/Catalog.java
@@ -0,0 +1,440 @@
+package org.onap.sdc.dcae.catalog;
+
+import java.net.URI;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.LinkedList;
+import java.util.HashMap;
+import java.util.EnumSet;
+
+import org.json.JSONObject;
+import org.onap.sdc.dcae.catalog.commons.Action;
+import org.onap.sdc.dcae.catalog.commons.Future;
+import org.onap.sdc.dcae.catalog.commons.Futures;
+import org.onap.sdc.dcae.catalog.commons.Proxies;
+
+
+import org.json.JSONArray;
+
+/*
+ *
+ */
+public interface Catalog {
+
+
+ public abstract URI getUri();
+
+ public abstract String namespace();
+
+ public abstract boolean same(Catalog theCatalog);
+
+ public abstract <T> T proxy(JSONObject theData, Class<T> theType);
+
+
+ /* Base class for all Catalog objects.
+ */
+ public static interface Element<T extends Element<T>> {
+
+ /**
+ * provide a typed 'self' reference
+ */
+ public default T self() { return (T)this; }
+
+ /**
+ */
+ public default Class<T> selfClass() {
+ return (Class<T>)getClass().getInterfaces()[0];
+ }
+
+ /* */
+ public Catalog catalog();
+
+ /**
+ */
+ public String id();
+
+ /**
+ * Direct access to the underlying JSON object.
+ * Warning: Modifications to the JSON object are reflected in the Element.
+ */
+ public JSONObject data();
+
+ /**
+ * Provides the labels of the artifacts (we use labels to type/classify the
+ * neo4j artifacts, nodes and edges.
+ * Currently not all queries retrieve the labels.
+ */
+ public String[] labels();
+
+ /* Allows for typed deep exploration of the backing JSON data structure
+ * <pre>
+ * {@code
+ * element("type", Type.class);
+ * }
+ * </pre>
+ *
+ * @arg theName name of a JSON entry ; It must map another JSONObject.
+ * @arg theType the expected wrapping catalog artifact type
+ * @return the JSON entry wrapped in the specified type
+ */
+ public default <E extends Element<E>> E element(String theName, Class<E> theType) {
+ JSONObject elemData = data().optJSONObject(theName);
+ if (elemData == null)
+ return null;
+ else
+ return catalog().proxy(elemData, theType);
+ }
+
+ /* Similar to {@link #element(String,Class)} but for collection wrapping.
+ * Example:
+ * <pre>
+ * {@code
+ * element("nodes", Nodes.class);
+ * }
+ * </pre>
+ */
+ public default <E extends Elements> E elements(String theName, Class<E> theType) {
+ //throws ReflectiveOperationException {
+ JSONArray elemsData = data().optJSONArray(theName);
+ if (elemsData == null) {
+ return null;
+ }
+ else {
+ Class etype = Proxies.typeArgument(theType);
+ Elements elems = null;
+ try {
+ elems = theType.newInstance();
+ }
+ catch (ReflectiveOperationException rox) {
+ throw new RuntimeException("Failed to instantiate " + theType, rox);
+ }
+
+ try{
+ for (Iterator i = elemsData.iterator(); i.hasNext();) {
+ JSONObject elemData = (JSONObject)i.next();
+ elems.add(catalog().proxy(elemData, etype));
+ }
+ }
+ catch(Exception e){
+ throw new RuntimeException("Failed to fetch json data ", e);
+ }
+ return (E)elems;
+ }
+ }
+
+ /*
+ */
+ public default boolean same(Element theElem) {
+ return this.catalog().same(theElem.catalog()) &&
+ this.id().equals(theElem.id());
+ }
+ }
+
+ /*
+ * Base class for all collections of elements.
+ */
+ public static class Elements<T extends Element>
+ extends LinkedList<T> {
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("[");
+ for (Element el: this) {
+ sb.append(el.selfClass().getSimpleName())
+ .append("(")
+ .append(el.data())
+ .append("),");
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+ }
+
+ /*
+ * We need this contraption in order to store a mix of Folders and CatalogItem
+ * instances (Elements in self is not good because it is defined around a
+ * type variable so we cannot use reflection to determine the type at runtime
+ * - generics are resolved compile time)
+ */
+ public static class Mixels extends Elements<Element> {
+ }
+
+ /*
+ */
+ public static interface Item<T extends Item<T>> extends Element<T> {
+
+ public String name();
+
+ public String description();
+
+ /* catalog item native identifier */
+ public String itemId();
+
+ /* similar to @ItemAction#withModels
+ */
+ default public Future<Templates> models() {
+ Templates t = elements("models", Templates.class);
+ if (t != null)
+ return Futures.succeededFuture(t);
+ else
+ return Futures.advance(catalog().item(itemId())
+ .withModels()
+ .execute(),
+ item -> (Templates)item.elements("models", Templates.class));
+ }
+
+ /* similar to @ItemAction#withAnnotations
+ */
+ default public Future<Annotations> annotations() {
+ Annotations a = elements("annotations", Annotations.class);
+ if (a != null)
+ return Futures.succeededFuture(a);
+ else
+ return Futures.advance(catalog().item(itemId())
+ .withAnnotations()
+ .execute(),
+ item -> (Annotations)item.elements("annotations", Annotations.class));
+ }
+ }
+
+ /*
+ * Collection of catalog items.
+ */
+ public static class Items extends Elements<Item> {
+ }
+
+ /*
+ */
+ public static interface Folder extends Element<Folder> {
+
+ public String name();
+
+ public String description();
+
+ public String itemId();
+
+ /* the namespace is immutable */
+ public default String namespace() {
+ return catalog().namespace();
+ }
+
+ /*
+ */
+ default public Future<Items> items() {
+ Items i = elements("items", Items.class);
+ if (i != null)
+ return Futures.succeededFuture(i);
+ else
+ return Futures.advance(catalog().folder(itemId())
+ .withItems()
+ .execute(),
+ folder -> (Items)folder.elements("items", Items.class));
+ }
+
+ /*
+ */
+ default public Future<Folders> parts() {
+ Folders f = elements("parts", Folders.class);
+ if (f != null)
+ return Futures.succeededFuture(f);
+ else
+ return Futures.advance(catalog().folder(itemId())
+ .withParts()
+ .execute(),
+ folder -> (Folders)folder.elements("parts", Folders.class));
+ }
+
+ /*
+ */
+ public Future<Folders> partof();
+
+ }
+
+
+ public static class Folders extends Elements<Folder> {
+ }
+
+ //no predefined properties here
+ public static interface Annotation extends Element<Annotation> {
+
+ public default String namespace() {
+ return catalog().namespace();
+ }
+ }
+
+ public static class Annotations extends Elements<Annotation> {
+ }
+
+ /**
+ * A TOSCA teamplate.
+ * When a deep loading method is used to obtain a Template its collection
+ * of inputs and nodes will be immediately available (and 'cached' within
+ * the backing JSON object). It can be retrieved through a call to
+ * {@link Element#elements(String,Class)} as in:
+ * elements("inputs", Inputs.class)
+ * or
+ * elements("nodes", Nodes.class)
+ *
+ * The same result will be obtained through one of the methods of the
+ * navigation interface, {@link #inputs()} or {@link #nodes()}; in this case
+ * the result does not become part of the backing JSONObject.
+ */
+ public static interface Template extends Element<Template> {
+
+ public String name();
+
+ public String version();
+
+ public String description();
+
+ }
+
+ /**
+ * Collection of {@link Catalog.Template template} instances.
+ */
+ public static class Templates extends Elements<Template> {
+ }
+
+
+ /**
+ * A TOSCA type declaration.
+ */
+ public interface Type extends Element<Type> {
+
+ public String name();
+
+ /**
+ * Allows navigation to the parent {@link Catalog.Type type}, if any.
+ */
+ public Future<Type> derivedfrom();
+
+ }
+
+ /**
+ * Collection of {@link Catalog.Type type} instances.
+ */
+ public static class Types extends Elements<Type> {
+ }
+
+
+ public static interface TemplateAction extends Action<Template> {
+
+ public TemplateAction withInputs();
+
+ public TemplateAction withOutputs();
+
+ public TemplateAction withNodes();
+
+ public TemplateAction withNodeProperties();
+
+ public TemplateAction withNodeRequirements();
+
+ public TemplateAction withNodePropertiesAssignments();
+
+ public TemplateAction withNodeCapabilities();
+
+ public TemplateAction withNodeCapabilityProperties();
+
+ public TemplateAction withNodeCapabilityPropertyAssignments();
+
+ public TemplateAction withPolicies();
+
+ public TemplateAction withPolicyProperties();
+
+ public TemplateAction withPolicyPropertiesAssignments();
+
+ @Override
+ public Future<Template> execute();
+
+ }
+
+ /*
+ */
+ public static interface TypeAction extends Action<Type> {
+
+ public TypeAction withHierarchy();
+
+ public TypeAction withRequirements();
+
+ public TypeAction withCapabilities();
+
+ @Override
+ public Future<Type> execute();
+
+ }
+
+ /*
+ */
+ public static interface FolderAction extends Action<Folder> {
+
+ public FolderAction withAnnotations();
+
+ public FolderAction withAnnotations(String theSelector);
+
+ public FolderAction withItems();
+
+ public FolderAction withItemAnnotations();
+
+ public FolderAction withItemAnnotations(String theSelector);
+
+ public FolderAction withItemModels();
+
+ public FolderAction withParts();
+
+ public FolderAction withPartAnnotations();
+
+ public FolderAction withPartAnnotations(String theSelector);
+
+ @Override
+ public Future<Folder> execute();
+ }
+
+ /*
+ */
+ public static interface ItemAction<T extends Item> extends Action<T> {
+
+ public ItemAction<T> withModels();
+
+ public ItemAction<T> withAnnotations();
+
+ @Override
+ public Future<T> execute();
+
+ }
+
+ /**
+ */
+ public abstract Future<Folders> roots();
+
+ /**
+ */
+ public abstract Future<Folders> rootsByLabel(String theLabel);
+
+ /**
+ */
+ public abstract Future<Mixels> lookup(JSONObject theSelector);
+
+ public abstract Future<Mixels> lookup(String theAnnotation, JSONObject theSelector);
+
+ /**
+ */
+ public abstract FolderAction folder(String theFolderId);
+
+ /**
+ */
+ public abstract <T extends Item> ItemAction<T> item(String theItemId);
+
+ /**
+ */
+ public abstract TemplateAction template(String theTemplateId);
+
+ /**
+ */
+ public abstract TypeAction type(String theNamespace, String theTypeName);
+
+
+
+}
diff --git a/dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCCatalog.java b/dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCCatalog.java
new file mode 100644
index 0000000..e08f3a6
--- /dev/null
+++ b/dcaedt_catalog/api/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCCatalog.java
@@ -0,0 +1,1227 @@
+package org.onap.sdc.dcae.catalog.asdc;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.JXPathNotFoundException;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.onap.sdc.common.onaplog.Enums.LogLevel;
+import org.onap.sdc.common.onaplog.OnapLoggerDebug;
+import org.onap.sdc.dcae.catalog.Catalog;
+import org.onap.sdc.dcae.catalog.commons.*;
+import org.onap.sdc.dcae.checker.*;
+
+import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+public class ASDCCatalog implements Catalog {
+
+ private
+ static final String JXPATH_NOT_FOUND_EXCEPTION = "JXPathNotFoundException {}";
+ private
+ static final String OCCURRENCES = "occurrences";
+ private
+ static final String TOPOLOGY_TEMPLATE_NODE_TEMPLATES = "/topology_template/node_templates";
+ private
+ static final String NODES_NAME = "/nodes[name='";
+ private
+ static final String ITEM_ID = "itemId";
+ private
+ static final String LABELS = "labels";
+ private
+ static final String ARTIFACT_URL = "artifactURL";
+ private
+ static final String CAPABILITY = "capability";
+ private
+ static final String DATABASE = "Database";
+ private
+ static final String COLLECTOR = "Collector";
+ private
+ static final String MICROSERVICE = "Microservice";
+ private
+ static final String ANALYTICS = "Analytics";
+ private
+ static final String POLICY = "Policy";
+ private
+ static final String SOURCE = "Source";
+ private
+ static final String UTILITY = "Utility";
+ private
+ static final String NAME = "name";
+ private
+ static final String ID = "id";
+ private
+ static final String ARTIFACT_NAME = "artifactName";
+ private
+ static final String DESCRIPTION = "description";
+ private
+ static final String MODELS = "models";
+ private
+ static final String ARTIFACTS = "artifacts";
+ private
+ static final String ITEMS = "items";
+ private
+ static final String PROPERTIES = "']/properties";
+ private
+ static final String TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 = "/topology_template/node_templates/";
+ private
+ static final String PROPERTIES_NAME = "']/properties[name='";
+ private
+ static final String CAPABILITIES = "']/capabilities";
+ private
+ static final String CAPABILITIES_NAME = "']/capabilities[name='";
+
+ private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
+
+ private ASDC asdc;
+
+ private JSONObject folders = new JSONObject();
+ private String[] folderFields = new String[] {ID, ITEM_ID, NAME};
+
+ private ProxyBuilder proxies;
+ private Map<Target, JXPathContext> contexts = new HashMap<Target, JXPathContext>();
+
+ // resource and its catalog
+ private Map<UUID, org.onap.sdc.dcae.checker.Catalog> catalogs = new HashMap<UUID, org.onap.sdc.dcae.checker.Catalog>();
+
+ public ASDCCatalog(URI theURI) {
+
+ this.asdc = new ASDC();
+ this.asdc.setUri(theURI);
+
+ initFolders();
+
+ this.proxies = new ProxyBuilder().withConverter(v -> v == null ? null : UUID.fromString(v.toString()), UUID.class)
+ .withExtensions(
+ new ImmutableMap.Builder<String, BiFunction<Proxy, Object[], Object>>().put("data", (proxy, args) -> proxy.data())
+ .build()).withContext(new ImmutableMap.Builder<String, Object>().put("catalog", this).build());
+ }
+
+ private void initFolders() {
+
+ JSONArray labels = new JSONArray();
+ labels.put("Folder");
+ labels.put("DCAE");
+ labels.put("Superportfolio"); // for CCD compatibility
+
+ folders.put(DATABASE, new JSONObject().put(NAME, DATABASE).put(ID, "dcae_database")
+ .put(ITEM_ID, DATABASE).put(LABELS, labels));
+ folders.put(COLLECTOR, new JSONObject().put(NAME, COLLECTOR).put(ID, "dcae_collector")
+ .put(ITEM_ID, COLLECTOR).put(LABELS, labels));
+ folders.put(MICROSERVICE, new JSONObject().put(NAME, MICROSERVICE).put(ID, "dcae_microservice")
+ .put(ITEM_ID, MICROSERVICE).put(LABELS, labels));
+ folders.put(ANALYTICS, new JSONObject().put(NAME, ANALYTICS).put(ID, "dcae_analytics")
+ .put(ITEM_ID, ANALYTICS).put(LABELS, labels));
+ folders.put(POLICY, new JSONObject().put(NAME, POLICY).put(ID, "dcae_policy").put(ITEM_ID, POLICY)
+ .put(LABELS, labels));
+ folders.put(SOURCE, new JSONObject().put(NAME, SOURCE).put(ID, "dcae_source").put(ITEM_ID, SOURCE)
+ .put(LABELS, labels));
+ folders.put(UTILITY, new JSONObject().put(NAME, UTILITY).put(ID, "dcae_utility")
+ .put(ITEM_ID, UTILITY).put(LABELS, labels));
+ }
+
+ public URI getUri() {
+ return this.asdc.getUri();
+ }
+
+ public String namespace() {
+ return "asdc";
+ }
+
+ public boolean same(Catalog theCatalog) {
+ return true;
+ }
+
+ public <T> T proxy(JSONObject theData, Class<T> theType) {
+ return proxies.build(theData, theType);
+ }
+
+ /** */
+ public Future<Folders> roots() {
+
+ Folders roots = new Folders();
+ for (Iterator fi = folders.keys(); fi.hasNext();) {
+ roots.add(proxies.build(folders.getJSONObject((String) fi.next()), Folder.class));
+ }
+ return Futures.succeededFuture(roots);
+ }
+
+ /** */
+ public Future<Folders> rootsByLabel(String theLabel) {
+
+ Folders roots = new Folders();
+ for (Iterator fi = folders.keys(); fi.hasNext();) {
+ JSONObject folder = folders.getJSONObject((String) fi.next());
+ JSONArray labels = folder.getJSONArray(LABELS);
+
+ for (int i = 0; i < labels.length(); i++) {
+ if (labels.get(i).equals(theLabel)) {
+ roots.add(proxies.build(folder, Folder.class));
+ }
+ }
+ }
+ return Futures.succeededFuture(roots);
+ }
+
+ /** */
+ public Future<Mixels> lookup(JSONObject theSelector) {
+ return Futures.succeededFuture(new Mixels());
+ }
+
+ public Future<Mixels> lookup(String theAnnotation, JSONObject theSelector) {
+ return Futures.succeededFuture(new Mixels());
+ }
+
+ /** */
+ public ItemAction item(String theItemId) {
+ return new ResourceAction(UUID.fromString(theItemId));
+ }
+
+ /** */
+ public FolderAction folder(String theFolderId) {
+ return new FolderAction(theFolderId);
+ }
+
+ public TemplateAction template(String theId) {
+ return new TemplateAction(theId);
+ }
+
+ public TypeAction type(String theItemId, String theName) {
+ return new TypeAction(UUID.fromString(theItemId), theName);
+ }
+
+ protected static String resolveTargetName(Target theTarget) {
+ return (String) ((Map) ((Map) theTarget.getTarget()).get("metadata")).get("template_name");
+ }
+
+ protected Object resolve(Target theTarget, String thePath) {
+ try {
+ return contexts.get(theTarget).getValue(thePath);
+ } catch (JXPathNotFoundException pnfx) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "JXPathNotFoundException {}", pnfx);
+ return null;
+ }
+ }
+
+ // covers common TOSCA pattern of single entry maps
+ public Map.Entry<String, Map> toEntry(Object theValue) {
+ return (Map.Entry<String, Map>) ((Map) theValue).entrySet().iterator().next();
+ }
+
+ protected Map selectEntries(Map theOriginal, String... theKeys) {
+ Arrays.sort(theKeys);
+ Map selection = ((Set<Map.Entry>) theOriginal.entrySet()).stream()
+ .filter(e -> Arrays.binarySearch(theKeys, e.getKey().toString()) >= 0)
+ .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
+ return selection;
+ }
+
+ protected Map evictEntries(Map theOriginal, String... theKeys) {
+ Arrays.sort(theKeys);
+ Map selection = ((Set<Map.Entry>) theOriginal.entrySet()).stream()
+ .filter(e -> Arrays.binarySearch(theKeys, e.getKey().toString()) < 0)
+ .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
+ return selection;
+ }
+
+ protected MapBuilder renderEntry(Map.Entry theEntry, String... theKeys) {
+ MapBuilder out = new MapBuilder();
+ out.put(NAME, theEntry.getKey());
+
+ for (String key : theKeys) {
+ out.put(key, ((Map) theEntry.getValue()).get(key));
+ }
+ return out;
+ }
+
+ protected <T> Stream<T> stream(Iterator<T> theSource) {
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(theSource,
+ Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.IMMUTABLE), false);
+ }
+
+ private JSONArray selectModels(JSONArray theArtifacts) {
+ JSONArray models = new JSONArray();
+ if (theArtifacts == null) {
+ return models;
+ }
+
+ for (int i = 0; i < theArtifacts.length(); i++) {
+ JSONObject artifact = theArtifacts.getJSONObject(i);
+ String name = artifact.optString(ARTIFACT_NAME);
+ if (name != null && StringUtils.containsIgnoreCase(name, "template")) {
+ models.put(new JSONObject().putOpt(NAME, artifact.optString(ARTIFACT_NAME))
+ .putOpt("version", artifact.optString("artifactVersion"))
+ .putOpt(DESCRIPTION, artifact.optString("artifactType"))
+ .putOpt(ID, artifact.optString(ARTIFACT_URL))
+ .putOpt(ITEM_ID, artifact.optString(ARTIFACT_URL)));
+ }
+ }
+ return models;
+ }
+
+ private JSONObject patchResource(JSONObject theResource) {
+
+ theResource.remove("resources");
+ theResource.putOpt(ID, theResource.opt("uuid"));
+ theResource.putOpt(ITEM_ID, theResource.opt("uuid"));
+
+ return theResource;
+ }
+
+ private static void dumpTargets(String theDirName, Collection<Target> theTargets) {
+ try {
+ File targetDir = new File(theDirName);
+ if (!targetDir.exists() && !targetDir.mkdirs()) {
+ throw new IllegalStateException("Couldn't create dir: " + theDirName);
+ }
+ for (Target t : theTargets) {
+ FileWriter dump = new FileWriter(new File(theDirName, t.getName()));
+ IOUtils.copy(t.open(), dump);
+ dump.close();
+ }
+ } catch (IOException iox) {
+ debugLogger.log(LogLevel.DEBUG,"ASDCCatalog", "IOException {}", iox);
+ }
+ }
+
+ private static URI asURI(String theValue) {
+ try {
+ return new URI(theValue);
+ } catch (URISyntaxException urisx) {
+ throw new IllegalArgumentException("Invalid URI", urisx);
+ }
+ }
+
+ private static UUID asUUID(String theValue) {
+ return UUID.fromString(theValue);
+ }
+
+ private org.onap.sdc.dcae.checker.Catalog getCatalog(UUID theResourceId) {
+ return this.catalogs.get(theResourceId);
+ }
+
+ private String getArtifactVersion(JSONObject theData) {
+ return theData.getString("artifactVersion");
+ }
+
+ private String getArtifactName(JSONObject theData) {
+ return theData.getString(ARTIFACT_NAME);
+ }
+
+ private String getArtifactURL(JSONObject theData) {
+ return theData.getString(ARTIFACT_URL);
+ }
+
+ private URI getArtifactURI(JSONObject theData) {
+ return asURI(theData.getString(ARTIFACT_URL));
+ }
+
+ /** */
+ public class ResourceAction implements Catalog.ItemAction<Resource> {
+
+ private UUID iid;
+ private boolean doModels;
+
+ ResourceAction(UUID theItemId) {
+ this.iid = theItemId;
+ }
+
+ public ResourceAction withModels() {
+ this.doModels = true;
+ return this;
+ }
+
+ public ResourceAction withAnnotations() {
+ return this;
+ }
+
+ @Override
+ public Future<Resource> execute() {
+
+ return Futures.advance(asdc.getResource(this.iid, JSONObject.class), resourceData -> {
+ if (doModels) {
+ resourceData.put(MODELS, selectModels(resourceData.optJSONArray(ARTIFACTS)));
+ }
+ return proxies.build(patchResource(resourceData), Resource.class);
+ });
+ }
+
+ protected Future<JSONObject> executeRaw() {
+
+ return Futures.advance(asdc.getResource(this.iid, JSONObject.class), resourceData -> {
+ if (doModels) {
+ resourceData.put(MODELS, selectModels(resourceData.optJSONArray(ARTIFACTS)));
+ }
+ return resourceData;
+ }, resourceError -> new RuntimeException("Failed to retrieve item " + this.iid, resourceError));
+ }
+ }
+
+ public class FolderAction implements Catalog.FolderAction {
+
+ private boolean doItemModels;
+ private String folderName;
+
+ // use the id/UUID of the folder ??
+ private FolderAction(String theFolderName) {
+ this.folderName = theFolderName;
+ }
+
+ public FolderAction withAnnotations() {
+ return this;
+ }
+
+ public FolderAction withAnnotations(String theSelector) {
+ return this;
+ }
+
+ public FolderAction withItems() {
+ return this;
+ }
+
+ public FolderAction withItemAnnotations() {
+ return this;
+ }
+
+ public FolderAction withItemAnnotations(String theSelector) {
+ return this;
+ }
+
+ public FolderAction withItemModels() {
+ doItemModels = true;
+ return this;
+ }
+
+ public FolderAction withParts() {
+ return this;
+ }
+
+ public FolderAction withPartAnnotations() {
+ return this;
+ }
+
+ public FolderAction withPartAnnotations(String theSelector) {
+ return this;
+ }
+
+ @Override
+ public Future<Folder> execute() {
+
+ JSONObject folder = folders.optJSONObject(this.folderName);
+ if (folder == null) {
+ return Futures.failedFuture(new RuntimeException("No such folder " + this.folderName));
+ }
+
+ final JSONObject folderView = new JSONObject(folder, folderFields);
+
+ return Futures.advance(asdc.getResources(JSONArray.class, "DCAE Component", this.folderName),
+ resourcesData -> {
+
+ Actions.CompoundAction<Resource> itemsAction = new Actions.BasicCompoundAction<Resource>();
+ for (int i = 0; i < resourcesData.length(); i++) {
+ JSONObject resource = resourcesData.getJSONObject(i);
+
+ if (doItemModels) {
+ itemsAction
+ .addAction(new ResourceAction(asUUID(resource.getString("uuid"))).withModels());
+ } else {
+ folderView.append(ITEMS, patchResource(resource));
+ }
+ }
+
+ try {
+ List<Resource> items = itemsAction.execute().waitForResult();
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Number of DCAE item for : {} is {}", this.folderName, items.size());
+
+ for (Resource res : filterLatestVersion(items)) {
+ folderView.append(ITEMS, patchResource(res.data()));
+ }
+ } catch (Exception x) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Exception {}", x);
+ throw new RuntimeException("Failed to retrieve folder items", x);
+ }
+
+ return proxies.build(folderView, Folder.class);
+ }, resourcesError -> new RuntimeException("Failed to retrieve resources", resourcesError));
+ }
+
+ public Collection<Resource> filterLatestVersion(Collection<Resource> items) throws IllegalArgumentException {
+ if (items == null) {
+ throw new IllegalArgumentException("null is not acceptable as a list of items");
+ }
+ Map<UUID, Resource> itemsMap = new HashMap<UUID, Resource>(items.size());
+ for (Resource r : items) {
+ if (itemsMap.containsKey(r.invariantUUID()) && isNewerVersion(itemsMap, r)) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Avoiding adding item {} since it has a advanced version already", r.toString());
+ continue;
+ }
+ itemsMap.put(r.invariantUUID(), r);
+ }
+ return itemsMap.values();
+ }
+
+ private boolean isNewerVersion(Map<UUID, Resource> itemsMap, Resource r) {
+ return Float.valueOf(itemsMap.get(r.invariantUUID()).version()) > Float.valueOf(r.version());
+ }
+
+ }
+
+ /** */
+ public class TemplateAction implements Catalog.TemplateAction {
+
+ private String artifactId;
+ private Target target;
+ private org.onap.sdc.dcae.checker.Catalog catalog;
+ private JXPathContext ctx = JXPathContext.newContext(new HashMap());
+
+ private boolean doNodes, doNodeProperties, doNodePropertiesAssignments, doNodeRequirements, doNodeCapabilities,
+ doNodeCapabilityProperties, doNodeCapabilityPropertyAssignments;
+
+ protected TemplateAction(Target theTarget) {
+ this.target = theTarget;
+ }
+
+ /*
+ * expected to be the relative url provided by asdc for the template
+ * artifact
+ */
+ protected TemplateAction(String theArtifactId) {
+ this.artifactId = theArtifactId;
+ }
+
+ public TemplateAction withInputs() {
+ return this;
+ }
+
+ public TemplateAction withOutputs() {
+ return this;
+ }
+
+ public TemplateAction withNodes() {
+ this.doNodes = true;
+ return this;
+ }
+
+ protected TemplateAction doNodes() {
+ if (!this.doNodes) {
+ return this;
+ }
+
+ Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
+ if (nodes == null) {
+ return this;
+ }
+
+ ctx.setValue("/nodes",
+ nodes.entrySet().stream()
+ .map(nodeEntry -> new MapBuilder().put(NAME, ((Map.Entry) nodeEntry).getKey())
+ .put(DESCRIPTION, this.artifactId)
+ .putAll(selectEntries((Map) ((Map.Entry) nodeEntry).getValue(), "type")).build())
+ .collect(Collectors.toList()));
+
+ return this;
+ }
+
+ // pre-requisite: a call to 'withNodes'
+ public TemplateAction withNodeProperties() {
+ this.doNodeProperties = true;
+ return this;
+ }
+
+ protected TemplateAction doNodeProperties() {
+ if (!this.doNodeProperties) {
+ return this;
+ }
+
+ Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
+ if (nodes == null) {
+ return this;
+ }
+
+ nodes.entrySet().stream().forEach(node -> ctx.setValue(
+ NODES_NAME + ((Map.Entry) node).getKey() + PROPERTIES,
+ stream(catalog.facets(Construct.Node, Facet.properties,
+ ((Map) ((Map.Entry) node).getValue()).get("type").toString()))
+ .map(propEntry -> new MapBuilder().put(NAME, propEntry.getKey())
+ .putAll((Map) propEntry.getValue()).build())
+ .collect(Collectors.toList())));
+
+ return this;
+ }
+
+ // pre-requisite: a call to 'withNodesProperties'
+ public TemplateAction withNodePropertiesAssignments() {
+ this.doNodePropertiesAssignments = true;
+ return this;
+ }
+
+ protected TemplateAction doNodePropertiesAssignments() {
+ if (!this.doNodePropertiesAssignments) {
+ return this;
+ }
+
+ Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
+ if (nodes == null) {
+ return this;
+ }
+
+ nodes.entrySet().stream().forEach(node -> {
+ List nodeProps = null;
+ try {
+ nodeProps = (List) ctx.getValue(NODES_NAME + ((Map.Entry) node).getKey() + PROPERTIES);
+ } catch (JXPathNotFoundException pnfx) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
+ return;
+ }
+
+ nodeProps.stream().forEach(prop -> {
+ // pick from
+ String propPath = TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 + ((Map.Entry) node).getKey()
+ + "/properties/" + ((Map) prop).get(NAME);
+ Object propValue = resolve(this.target, propPath);
+ // to conform with the db based api we should analyze the
+ // value for function calls
+ // dump at ..
+ propPath = NODES_NAME + ((Map.Entry) node).getKey() + PROPERTIES_NAME
+ + ((Map) prop).get(NAME) + "']";
+ if (propValue != null) {
+ ctx.setValue(propPath + "/assignment",
+ new ImmutableMap.Builder().put("value", propValue).build());
+ }
+ });
+ });
+
+ return this;
+ }
+
+ protected Map renderRequirementDefinition(Map.Entry theReq) {
+ Map def = (Map) theReq.getValue();
+ return new MapBuilder().put(NAME, theReq.getKey())
+ // capability must be present
+ .put(CAPABILITY,
+ new MapBuilder().put(NAME, def.get(CAPABILITY))
+ .put(ID, this.target.getName() + "/" + def.get(CAPABILITY)).build())
+ .putAll(evictEntries(def, CAPABILITY)).build();
+ }
+
+ // TODO: see how this comes out of neo and match it
+ protected Map renderRequirementAssignment(Map.Entry theReq) {
+ Map def = (Map) theReq.getValue();
+ return new MapBuilder().put(NAME, theReq.getKey())
+ // capability must be present
+ .put(CAPABILITY,
+ new MapBuilder().put(NAME, def.get(CAPABILITY))
+ // we provide an id only if the capability
+ // points to a type
+ .putOpt(ID,
+ catalog.hasType(Construct.Capability, (String) def.get(CAPABILITY))
+ ? (this.target.getName() + "/" + def.get(CAPABILITY)) : null)
+ .build())
+ .putAll(evictEntries(def, CAPABILITY)).build();
+ }
+
+ public TemplateAction withNodeRequirements() {
+ this.doNodeRequirements = true;
+ return this;
+ }
+
+ TemplateAction doNodeRequirements() {
+ if (!this.doNodeRequirements) {
+ return this;
+ }
+
+ // requirements come first from the type and then can be further
+ // refined by their assignment within the
+ // node template
+ Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
+ if (nodes == null) {
+ return this;
+ }
+
+ // type
+ nodes.entrySet().stream()
+ .forEach(
+ node -> ctx
+ .setValue(
+ NODES_NAME
+ + ((Map.Entry) node)
+ .getKey()
+ + "']/requirements",
+ StreamSupport
+ .stream(Spliterators.spliteratorUnknownSize(
+ catalog.requirements(((Map) ((Map.Entry) node).getValue())
+ .get("type").toString()),
+ Spliterator.NONNULL | Spliterator.DISTINCT
+ | Spliterator.IMMUTABLE),
+ false)
+ .map((Map.Entry reqEntry) -> renderRequirementDefinition(reqEntry))
+ .collect(Collectors.toList())));
+
+ // merge assignments on top of definitions
+ nodes.entrySet().stream().forEach(node -> {
+ List nodeReqsAssigns = (List) resolve(this.target,
+ TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 + ((Map.Entry) node).getKey() + "/requirements");
+ if (nodeReqsAssigns == null) {
+ return;
+ }
+ nodeReqsAssigns.stream().forEach(req -> {
+ Map.Entry reqAssign = toEntry(req);
+ catalog.mergeDefinitions((Map) ctx.getValue(NODES_NAME + ((Map.Entry) node).getKey()
+ + "']/requirements[name='" + reqAssign.getKey() + "']"),
+ renderRequirementAssignment(reqAssign));
+ });
+ });
+
+ return this;
+ }
+
+ public TemplateAction withNodeCapabilities() {
+ this.doNodeCapabilities = true;
+ return this;
+ }
+
+ protected Map renderCapabilityDefinition(Map.Entry theCap) {
+ Map def = (Map) theCap.getValue();
+ return new MapBuilder().put(NAME, theCap.getKey())
+ .put("type",
+ new MapBuilder().put(NAME, def.get("type"))
+ .put(ID, this.target.getName() + "/" + def.get("type")).build())
+ .putAll(evictEntries(def, "properties", "type")).build();
+ }
+
+ TemplateAction doNodeCapabilities() {
+ if (!this.doNodeCapabilities) {
+ return this;
+ }
+
+ Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
+ if (nodes == null) {
+ return this;
+ }
+
+ // collect capabilities through the node type hierarchy
+
+ // we evict the properties from the node type capability declaration
+ // (when declaring a capability with the
+ // node type some re-definition of capability properties can take
+ // place).
+ nodes.entrySet().stream()
+ .forEach(node -> ctx.setValue(NODES_NAME + ((Map.Entry) node).getKey() + CAPABILITIES,
+
+ stream(catalog.facets(Construct.Node, Facet.capabilities,
+ ((Map) ((Map.Entry) node).getValue()).get("type").toString()))
+ .map((Map.Entry capEntry) -> renderCapabilityDefinition(capEntry))
+ .collect(Collectors.toList())));
+
+ return this;
+ }
+
+ public TemplateAction withNodeCapabilityProperties() {
+ this.doNodeCapabilityProperties = true;
+ return this;
+ }
+
+ TemplateAction doNodeCapabilityProperties() {
+
+ if (!this.doNodeCapabilityProperties) {
+ return this;
+ }
+
+ Map nodes = (Map) resolve(this.target, TOPOLOGY_TEMPLATE_NODE_TEMPLATES);
+ if (nodes == null) {
+ return this;
+ }
+
+ // pick up all the properties from the capability type hierarchy
+ // definition
+ nodes.entrySet().stream().forEach(node -> {
+ List nodeCapabilities = (List) ctx
+ .getValue(NODES_NAME + ((Map.Entry) node).getKey() + CAPABILITIES);
+ if (nodeCapabilities == null) {
+ return;
+ }
+
+ // collect properties from the capability type hierarchy
+ nodeCapabilities.stream().forEach(capability -> {
+ List capabilityProperties = StreamSupport
+ .stream(Spliterators.spliteratorUnknownSize(
+ catalog.facets(Construct.Capability, Facet.properties,
+ ((Map)((Map)capability).get("type")).get(NAME).toString()),
+ Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.IMMUTABLE), false)
+ .map((Map.Entry capEntry) -> new MapBuilder().put(NAME, capEntry.getKey())
+ .putAll((Map) capEntry.getValue()).build())
+ .collect(Collectors.toList());
+
+ if (!capabilityProperties.isEmpty()) {
+ ctx.setValue(NODES_NAME + ((Map.Entry) node).getKey() + CAPABILITIES_NAME
+ + ((Map) capability).get(NAME) + PROPERTIES, capabilityProperties);
+ }
+ });
+
+ // and go over the node type (hierarchy) and pick up any
+ // re-definitions from there.
+ StreamSupport
+ .stream(Spliterators.spliteratorUnknownSize(
+ catalog.facets(Construct.Node, Facet.capabilities,
+ ((Map) ((Map.Entry) node).getValue()).get("type").toString()),
+ Spliterator.NONNULL | Spliterator.DISTINCT | Spliterator.IMMUTABLE), false)
+ .forEach((Map.Entry capability) -> {
+ // for each capability property that has some node
+ // type level re-definition
+ Map properties = (Map) ((Map) capability.getValue()).get("properties");
+ if (properties == null) {
+ return;
+ }
+
+ properties.entrySet().stream().forEach(property -> {
+ String propertyLoc = NODES_NAME + ((Map.Entry) node).getKey()
+ + CAPABILITIES_NAME + ((Map) capability).get(NAME)
+ + PROPERTIES_NAME + ((Map.Entry) property).getKey() + "']";
+ ctx.setValue(propertyLoc, catalog.mergeDefinitions((Map) ctx.getValue(propertyLoc),
+ (Map) ((Map.Entry) property).getValue()));
+ });
+ });
+ });
+
+ return this;
+ }
+
+ public TemplateAction withNodeCapabilityPropertyAssignments() {
+ this.doNodeCapabilityPropertyAssignments = true;
+ return this;
+ }
+
+ TemplateAction doNodeCapabilityPropertyAssignments() {
+ if (!this.doNodeCapabilityPropertyAssignments) {
+ return this;
+ }
+
+ // this is a wasteful: we go over all declared
+ // nodes/capabilities/properties and check if there is an assigned
+ // value in the actual template. It is optimal to approach the
+ // problem from the other direction: go over delared
+ // assignments and set them in the output structure ..
+
+ List nodes = null;
+ try {
+ nodes = (List) ctx.getValue("/nodes");
+ } catch (JXPathNotFoundException pnfx) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
+ return this;
+ }
+
+ nodes.stream().forEach(node -> {
+ List capabilities = (List) ctx.getValue(NODES_NAME + ((Map) node).get(NAME) + CAPABILITIES);
+ if (capabilities == null) {
+ return;
+ }
+
+ capabilities.stream().forEach(capability -> {
+ List properties = null;
+ try {
+ properties = (List) ctx.getValue(NODES_NAME + ((Map) node).get(NAME)
+ + CAPABILITIES_NAME + ((Map) capability).get(NAME) + PROPERTIES);
+ } catch (JXPathNotFoundException pnfx) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
+ return;
+ }
+
+ properties.stream().forEach(property -> {
+ String location = NODES_NAME + ((Map) node).get(NAME) + CAPABILITIES_NAME
+ + ((Map) capability).get(NAME) + PROPERTIES_NAME + ((Map) property).get(NAME)
+ + "']/assignment";
+
+ // pick the value from the original
+ try {
+ Object assignment = resolve(this.target,
+ TOPOLOGY_TEMPLATE_NODE_TEMPLATES1 + ((Map) node).get(NAME) + "/capabilities/"
+ + ((Map) capability).get(NAME) + "/properties/"
+ + ((Map) property).get(NAME));
+ if (assignment != null) {
+ ctx.setValue(location, new ImmutableMap.Builder().put("value", assignment).build());
+ }
+ } catch (JXPathNotFoundException pnfx) {
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), JXPATH_NOT_FOUND_EXCEPTION, pnfx);
+ // it's ok, no assignment
+ }
+ });
+ });
+ });
+
+ return this;
+ }
+
+ public TemplateAction withPolicies() {
+ return this;
+ }
+
+ public TemplateAction withPolicyProperties() {
+ return this;
+ }
+
+ public TemplateAction withPolicyPropertiesAssignments() {
+ return this;
+ }
+
+ public Future<Template> execute() {
+
+ if (this.target == null) {
+
+ String[] parts = this.artifactId.split("/");
+ if (parts.length != 8) {
+ return Futures
+ .failedFuture(new Exception("Unexpected artifact id for template " + this.artifactId));
+ }
+
+ UUID resourceId = asUUID(parts[5]);
+ this.catalog = ASDCCatalog.this.catalogs.get(resourceId);
+
+ // if we find a catalog for this resource we have to figure out
+ // if it contains the required target ..
+
+ try {
+ JSONObject resource = new ResourceAction(resourceId).executeRaw().waitForResult();
+
+ Checker checker = new Checker();
+ TargetLocator locator = new ASDCLocator(resource.getJSONArray(ARTIFACTS),
+ ASDCCatalog.this.catalogs.get(resourceId));
+ checker.setTargetLocator(locator);
+
+ Target template = locator.resolve("template");
+ if (template == null) {
+ return Futures.failedFuture(new Exception("Failed to locate template in " + resource));
+ }
+
+ checker.check(template);
+
+ for (Target t : checker.targets()) {
+ if (t.getReport().hasErrors()) {
+ dumpTargets(resourceId.toString(), checker.targets());
+ return Futures.failedFuture(new Exception("Failed template validation: " + t.getReport()));
+ }
+ }
+
+ this.target = template;
+ this.catalog = checker.catalog();
+ ASDCCatalog.this.catalogs.put(resourceId, this.catalog);
+ // we should only be doing this if we discovered an update
+ // (by checking timestampts). Actually, we should
+ // only do the artifact fetching if we detect an update
+ ASDCCatalog.this.contexts.put(template, JXPathContext.newContext(template.getTarget()));
+ } catch (Exception x) {
+ return Futures.failedFuture(x);
+ }
+ }
+
+ this.doNodes().doNodeProperties().doNodePropertiesAssignments().doNodeRequirements().doNodeCapabilities()
+ .doNodeCapabilityProperties().doNodeCapabilityPropertyAssignments();
+
+ JSONObject pack = new JSONObject((Map) ctx.getContextBean()).put(NAME, this.target.getName().toString())
+ .put(ID, this.target.getLocation().toString())
+ .put(ITEM_ID, this.target.getLocation().toString());
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), pack.toString(2));
+
+ return Futures.succeededFuture(proxies.build(pack, Template.class));
+ }
+ }
+
+ public class TypeAction implements Catalog.TypeAction {
+
+ private String name;
+ private UUID resourceId;
+ private JXPathContext ctx;
+
+ private boolean doHierarchy = false, doRequirements = false, doCapabilities = false;
+
+ private TypeAction(UUID theResourceId, /* Construct theConstruct, */ String theName) {
+ this.resourceId = theResourceId;
+ this.name = theName;
+ }
+
+ public TypeAction withHierarchy() {
+ this.doHierarchy = true;
+ return this;
+ }
+
+ TypeAction doHierarchy(org.onap.sdc.dcae.checker.Catalog theCatalog) {
+ if (!this.doHierarchy) {
+ return this;
+ }
+
+ ctx.setValue("/hierarchy",
+ stream(theCatalog.hierarchy(Construct.Node, this.name)).skip(1) // skip
+ // self
+ .map((Map.Entry type) -> new MapBuilder()
+ .put(NAME, type.getKey()).put(ID, resourceId + "/" + type.getKey())
+ .putOpt(DESCRIPTION, ((Map) type.getValue()).get(DESCRIPTION)).build())
+ // renderEntry((Map.Entry)type,
+ // "description").build())
+ .collect(Collectors.toList()));
+ return this;
+ }
+
+ public TypeAction withRequirements() {
+ this.doRequirements = true;
+ return this;
+ }
+
+ TypeAction doRequirements(org.onap.sdc.dcae.checker.Catalog theCatalog) {
+ if (!this.doRequirements) {
+ return this;
+ }
+
+ ctx.setValue("requirements", stream(theCatalog.requirements(this.name)).map((Map.Entry req) -> {
+ String capability = (String) ((Map) req.getValue()).get(CAPABILITY),
+ node = (String) ((Map) req.getValue()).get(CAPABILITY);
+ return new MapBuilder().put(NAME, req.getKey()).put(ID, resourceId + "/" + req.getKey())
+ .put(OCCURRENCES, ((Map) req.getValue()).get(OCCURRENCES))
+ .put(CAPABILITY,
+ new MapBuilder().put(NAME, capability)
+ // if the capability points to a
+ // capability type then encode
+ // the type reference, else it is a name
+ // (within a node type)
+ .put(ID,
+ getCatalog(resourceId).hasType(Construct.Capability, capability)
+ ? (resourceId + "/" + capability) : capability.toString())
+ .build())
+ .put("node", new MapBuilder().putOpt(NAME, node).putOpt(ID, node == null ? null
+ : (resourceId + "/" + node)).buildOpt())
+ .put("relationship", ((Map) req.getValue()).get("relationship"))
+ // renderEntry((Map.Entry)requirement, "occurrences",
+ // "node", "capability", "relationship")
+ .build();
+ }).collect(Collectors.toList()));
+
+ return this;
+ }
+
+ public TypeAction withCapabilities() {
+ this.doCapabilities = true;
+ return this;
+ }
+
+ TypeAction doCapabilities(org.onap.sdc.dcae.checker.Catalog theCatalog) {
+ if (!this.doCapabilities) {
+ return this;
+ }
+
+ ctx.setValue("capabilities",
+ stream(theCatalog
+ .facets(Construct.Node, Facet.capabilities,
+ this.name))
+ .map((Map.Entry capability) -> new MapBuilder()
+ .put(NAME, capability.getKey()).put("type",
+ new MapBuilder()
+ .put(NAME, ((Map) capability.getValue())
+ .get("type"))
+ .put(ID,
+ resourceId + "/"
+ + ((Map) capability.getValue())
+ .get("type"))
+ .build())
+ .put(OCCURRENCES,
+ ((Map) capability.getValue()).get(OCCURRENCES))
+ .putOpt("validSourceTypes",
+ ((Map) capability.getValue()).get("validSourceTypes"))
+ .build()
+ // renderEntry((Map.Entry)capability,
+ // "occurrences",
+ // "validSourceTypes")
+ ).collect(Collectors.toList()));
+ return this;
+ }
+
+ public Future<Type> execute() {
+ org.onap.sdc.dcae.checker.Catalog catalog = ASDCCatalog.this.catalogs.get(this.resourceId);
+ if (catalog == null) {
+ return Futures.failedFuture(new Exception("No catalog available for resource " + this.resourceId
+ + ". You might want to fetch the model first."));
+ }
+
+ if (!catalog.hasType(Construct.Node, this.name)) {
+ return Futures.failedFuture(
+ new Exception("No " + this.name + " type in catalog for resource " + this.resourceId));
+ }
+
+ this.ctx = JXPathContext
+ .newContext(new MapBuilder().put(NAME, this.name).put(ID, this.resourceId + "/" + this.name)
+ .put(ITEM_ID, this.resourceId + "/" + this.name).build());
+
+ this.doHierarchy(catalog).doRequirements(catalog).doCapabilities(catalog);
+
+ JSONObject pack = new JSONObject((Map) this.ctx.getContextBean());
+ debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), pack.toString(2));
+
+ return Futures.succeededFuture(proxies.build((Map) ctx.getContextBean(), Type.class));
+ }
+ }
+
+ public static interface Resource extends Catalog.Item<Resource> {
+
+ @Override
+ @Proxy.DataMap(map = "uuid")
+ public String id();
+
+ public UUID uuid();
+
+ public UUID invariantUUID();
+
+ public String category();
+
+ public String subCategory();
+
+ public String lastUpdaterFullName();
+
+ public String version();
+
+ @Proxy.DataMap(proxy = true, elementType = Artifact.class)
+ public Artifacts artifacts();
+
+ }
+
+ public static class Resources extends Elements<Resource> {
+ }
+
+ public static interface Artifact extends Catalog.Element<Artifact> {
+
+ @Proxy.DataMap(map = ARTIFACT_NAME)
+ public String name();
+
+ @Proxy.DataMap(map = "artifactType")
+ public String type();
+
+ @Proxy.DataMap(map = "artifactDescription")
+ public String description();
+
+ @Proxy.DataMap(map = "artifactUUID")
+ public UUID uuid();
+
+ @Proxy.DataMap(map = "artifactVersion")
+ public int version();
+
+ }
+
+ public static class Artifacts extends Elements<Artifact> {
+ }
+
+ public class ASDCLocator implements TargetLocator {
+
+ private JSONArray artifacts;
+ private org.onap.sdc.dcae.checker.Catalog catalog;
+
+ private ASDCLocator(JSONArray theArtifacts, org.onap.sdc.dcae.checker.Catalog theCatalog) {
+ this.artifacts = theArtifacts;
+ this.catalog = theCatalog;
+ }
+
+ public boolean addSearchPath(URI theURI) {
+ return false;
+ }
+
+ public boolean addSearchPath(String thePath) {
+ return false;
+ }
+
+ public Iterable<URI> searchPaths() {
+ return Collections.emptySet();
+ }
+
+ public Target resolve(String theName) {
+ JSONObject targetArtifact = null;
+
+ for (int i = 0; i < this.artifacts.length(); i++) {
+ JSONObject artifact = this.artifacts.getJSONObject(i);
+ String artifactName = artifact.getString(ARTIFACT_NAME);
+ if (StringUtils.containsIgnoreCase(artifactName, theName)) {
+ targetArtifact = artifact;
+ }
+ }
+
+ if (targetArtifact == null) {
+ return null;
+ }
+
+ ASDCTarget target = null;
+ if (this.catalog != null) {
+ // this is the caching!!
+ target = (ASDCTarget) this.catalog.getTarget(ASDCCatalog.this.getArtifactURI(targetArtifact));
+ if (target != null && target.getVersion().equals(ASDCCatalog.this.getArtifactVersion(targetArtifact))) {
+ return target;
+ }
+ }
+
+ return new ASDCTarget(targetArtifact);
+ }
+ }
+
+ public class ASDCTarget extends Target {
+
+ private String content;
+ private JSONObject artifact;
+
+ private ASDCTarget(JSONObject theArtifact) {
+ super(ASDCCatalog.this.getArtifactName(theArtifact), ASDCCatalog.this.getArtifactURI(theArtifact));
+ this.artifact = theArtifact;
+ }
+
+ // here is a chance for caching within the catalog! Do not go fetch the
+ // artifact if it has not been changed since the
+ // last fetch.
+
+ @Override
+ public Reader open() throws IOException {
+ if (this.content == null) {
+ try {
+ this.content = ASDCCatalog.this.asdc
+ .fetch(ASDCCatalog.this.getArtifactURL(this.artifact), String.class).waitForResult();
+ } catch (Exception x) {
+ throw new IOException("Failed to load " + ASDCCatalog.this.getArtifactURL(this.artifact), x);
+ }
+ }
+
+ // should return immediately a reader blocked until content
+ // available .. hard to handle errors
+ return new StringReader(this.content);
+ }
+
+ public String getVersion() {
+ return ASDCCatalog.this.getArtifactVersion(this.artifact);
+ }
+
+ }
+
+ public static void main(String[] theArgs) throws Exception {
+
+ ASDCCatalog catalog = new ASDCCatalog(new URI(theArgs[0]));
+
+ Folder f = catalog.folder(theArgs[1]).withItems().withItemModels().execute().waitForResult();
+
+ debugLogger.log(LogLevel.DEBUG, ASDCCatalog.class.getName(), "folder: {}", f.data());
+
+ Resources items = f.elements(ITEMS, Resources.class);
+ if (items != null) {
+ for (Resource item : items) {
+ debugLogger.log(LogLevel.DEBUG, ASDCCatalog.class.getName(), "\titem: {} : {}",item.name(), item.data());
+ Templates templates = item.elements(MODELS, Templates.class);
+ if (templates != null) {
+ for (Template t : templates) {
+ Template ft = catalog.template(t.id()).withNodes().withNodeProperties()
+ .withNodePropertiesAssignments().execute().waitForResult();
+
+ debugLogger.log(LogLevel.DEBUG, ASDCCatalog.class.getName(), "template data: {}", ft.data());
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/dcaedt_catalog/api/src/main/resources/log4j.properties b/dcaedt_catalog/api/src/main/resources/log4j.properties
new file mode 100644
index 0000000..6e159e5
--- /dev/null
+++ b/dcaedt_catalog/api/src/main/resources/log4j.properties
@@ -0,0 +1,8 @@
+log4j.rootLogger=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%5p [%c] %m%n
+
+log4j.logger.org.apache.http=DEBUG
+log4j.logger.org.apache.http.wire=ERROR \ No newline at end of file
diff --git a/dcaedt_catalog/api/src/test/java/org/onap/sdc/dcae/catalog/ASDCCatalogTest.java b/dcaedt_catalog/api/src/test/java/org/onap/sdc/dcae/catalog/ASDCCatalogTest.java
new file mode 100644
index 0000000..fcd92f0
--- /dev/null
+++ b/dcaedt_catalog/api/src/test/java/org/onap/sdc/dcae/catalog/ASDCCatalogTest.java
@@ -0,0 +1,88 @@
+package org.onap.sdc.dcae.catalog;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.UUID;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.onap.sdc.dcae.catalog.asdc.ASDCCatalog;
+import org.onap.sdc.dcae.catalog.asdc.ASDCCatalog.FolderAction;
+import org.onap.sdc.dcae.catalog.asdc.ASDCCatalog.Resource;
+
+import static org.mockito.Mockito.*;
+
+
+public class ASDCCatalogTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private static FolderAction getTarget() {
+ ASDCCatalog catalog = mock(ASDCCatalog.class);
+ when(catalog.folder("test")).thenCallRealMethod();
+ FolderAction target = catalog.folder("test");
+ return target;
+ }
+
+ @Test
+ public void filterLatestVersion_null_throwIllegalArgumentException() {
+ // arrange
+ FolderAction target = getTarget();
+ // assert
+ thrown.expect(IllegalArgumentException.class);
+ // act
+ target.filterLatestVersion(null);
+ }
+
+ @Test
+ public void filterLatestVersion_emptyItemsList_emptyItemsList() throws URISyntaxException {
+ // arrange
+ FolderAction target = getTarget();
+ // act
+ Collection<Resource> result = target.filterLatestVersion(new ArrayList<>());
+ // assert
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void filterLatestVersion_itemWithTwoVersions_itemWithLatestVersion() {
+ // arrange
+ FolderAction target = getTarget();
+
+ UUID invariantUUID = UUID.randomUUID();
+ Resource r1v1 = mock(Resource.class);
+ Resource r1v2 = mock(Resource.class);
+ when(r1v1.invariantUUID()).thenReturn(invariantUUID);
+ when(r1v2.invariantUUID()).thenReturn(invariantUUID);
+ when(r1v1.version()).thenReturn("1.0");
+ when(r1v2.version()).thenReturn("2.0");
+ ArrayList<Resource> listItemWithTwoVersions = new ArrayList<Resource>(Arrays.asList(r1v1, r1v2));
+ // act
+ Collection<Resource> result = target.filterLatestVersion(listItemWithTwoVersions);
+ // assert
+ assertThat(result).containsExactly(r1v2);
+ }
+
+ @Test
+ public void filterLatestVersion_2distinctItems_2distinctItems() {
+ // arrange
+ FolderAction target = getTarget();
+
+ Resource r1 = mock(Resource.class);
+ Resource r2 = mock(Resource.class);
+ when(r1.invariantUUID()).thenReturn(UUID.randomUUID());
+ when(r2.invariantUUID()).thenReturn(UUID.randomUUID());
+ ArrayList<Resource> listOfTwoDistinctItems = new ArrayList<Resource>(Arrays.asList(r1, r2));
+ // act
+ Collection<Resource> result = target.filterLatestVersion(listOfTwoDistinctItems);
+ // assert
+ assertThat(result).containsExactlyInAnyOrder(r1, r2);
+ }
+
+}