aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore127
-rw-r--r--LICENSE.txt7
-rw-r--r--README.md7
-rw-r--r--pom.xml86
-rw-r--r--src/main/java/org/onap/nbi/Application.java13
-rw-r--r--src/main/java/org/onap/nbi/apis/status/StatusResource.java55
-rw-r--r--src/main/java/org/onap/nbi/apis/status/StatusService.java9
-rw-r--r--src/main/java/org/onap/nbi/apis/status/StatusServiceImpl.java28
-rw-r--r--src/main/java/org/onap/nbi/apis/status/model/ApplicationStatus.java55
-rw-r--r--src/main/java/org/onap/nbi/apis/status/model/StatusType.java30
-rw-r--r--src/main/java/org/onap/nbi/commons/BeanUtils.java39
-rw-r--r--src/main/java/org/onap/nbi/commons/JacksonFilter.java169
-rw-r--r--src/main/java/org/onap/nbi/commons/JsonRepresentation.java35
-rw-r--r--src/main/java/org/onap/nbi/commons/Query.java26
-rw-r--r--src/main/java/org/onap/nbi/commons/QueryParserUtils.java65
-rw-r--r--src/main/java/org/onap/nbi/commons/ReservedKeys.java18
-rw-r--r--src/main/java/org/onap/nbi/commons/Resource.java8
-rw-r--r--src/main/java/org/onap/nbi/commons/ResourceManagement.java149
-rw-r--r--src/main/resources/application.properties6
-rw-r--r--src/test/java/org/onap/nbi/apis/status/StatusTest.java41
20 files changed, 973 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a05f4a2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,127 @@
+#### OS related ####
+### Linux related ###
+*~
+
+# KDE directory preferences
+.directory
+
+### OSX related ###
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
+
+### Windows related ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+#### IDE related ####
+### Eclipse related ###
+*.pydevproject
+.metadata
+.gradle
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.factorypath
+.loadpath
+.classpath
+.project
+.springBeans
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+# TeXlipse plugin
+.texlipse
+
+### Idea related ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
+
+## Directory-based project format
+.idea/
+
+## File-based project format
+*.ipr
+*.iws
+*.iml
+
+## Additional for IntelliJ
+out/
+
+# generated by JIRA plugin
+atlassian-ide-plugin.xml
+
+### Netbeans related ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+nbactions.xml
+nb-configuration.xml
+
+### Notepad++ backups ###
+*.bak
+
+### Shell ###
+*.sh
+
+#### Tools & Languages related ####
+### Java related ###
+*.class
+
+# Package Files #
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Maven related ###
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+
+### Git related ###
+*.orig
+/.apt_generated/
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..e8cdcf3
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,7 @@
+Copyright (c) 2017 Orange. All rights reserved.
+===================================================================
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6e46f00
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+nbi
+===============
+NBI stands for NorthBound Interface. It brings to ONAP a set of API - at service level - that can be used by external systems as BSS for example. These API are based on TMForum API
+
+## License
+The Microservice Bus is released under version 2.0 of the [Apache License][].
+[Apache License]: http://www.apache.org/licenses/LICENSE-2.0
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..3c5bbbd
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>
+
+ <groupId>org.onap.nbi</groupId>
+ <artifactId>nbi-rest-services</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>nbi-rest-services</name>
+
+ <parent>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-parent</artifactId>
+ <version>1.5.10.RELEASE</version>
+ <relativePath /> <!-- lookup parent from repository -->
+ </parent>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <java.version>1.8</java.version>
+ </properties>
+
+ <licenses>
+ <license>
+ <name>Apache2</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-beanutils</groupId>
+ <artifactId>commons-beanutils</artifactId>
+ <version>1.9.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.4</version>
+ </dependency>
+
+ <!-- test -->
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- runtime dev -->
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-devtools</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+
+ </build>
+
+</project>
diff --git a/src/main/java/org/onap/nbi/Application.java b/src/main/java/org/onap/nbi/Application.java
new file mode 100644
index 0000000..0609f9c
--- /dev/null
+++ b/src/main/java/org/onap/nbi/Application.java
@@ -0,0 +1,13 @@
+package org.onap.nbi;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/apis/status/StatusResource.java b/src/main/java/org/onap/nbi/apis/status/StatusResource.java
new file mode 100644
index 0000000..f4b0bcd
--- /dev/null
+++ b/src/main/java/org/onap/nbi/apis/status/StatusResource.java
@@ -0,0 +1,55 @@
+package org.onap.nbi.apis.status;
+
+import org.onap.nbi.apis.status.model.ApplicationStatus;
+import org.onap.nbi.apis.status.model.StatusType;
+import org.onap.nbi.commons.JsonRepresentation;
+import org.onap.nbi.commons.ResourceManagement;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import javax.servlet.http.HttpServletRequest;
+
+
+@RestController
+@RequestMapping("/status")
+public class StatusResource extends ResourceManagement<ApplicationStatus> {
+
+ @Autowired
+ private StatusService statusService;
+
+ private JsonRepresentation fullRepresentation = new JsonRepresentation().add("name").add("status").add("version")
+ .add("components.name").add("components.status");
+
+ @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity<Object> status(HttpServletRequest request) {
+
+ ResponseEntity<Object> responseEntity = null;
+
+ final String[] splitPath = request.getRequestURI().split("/");
+
+ final String applicationName = splitPath[1];
+ final String applicationVersion = splitPath[3];
+
+ final ApplicationStatus applicationStatus = this.statusService.get(applicationName, applicationVersion);
+
+ final boolean isServiceFullyFunctional =
+ StatusType.OK.equals(applicationStatus.getStatus()) ? applicationStatus.getComponents().stream()
+ .allMatch(componentStatus -> StatusType.OK.equals(componentStatus.getStatus())) : false;
+
+ // filter object
+ Object response = this.getEntity(applicationStatus, fullRepresentation);
+
+ if (isServiceFullyFunctional) {
+ responseEntity = ResponseEntity.ok(response);
+ } else {
+ responseEntity = ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(response);
+ }
+
+ return responseEntity;
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/apis/status/StatusService.java b/src/main/java/org/onap/nbi/apis/status/StatusService.java
new file mode 100644
index 0000000..2309da4
--- /dev/null
+++ b/src/main/java/org/onap/nbi/apis/status/StatusService.java
@@ -0,0 +1,9 @@
+package org.onap.nbi.apis.status;
+
+import org.onap.nbi.apis.status.model.ApplicationStatus;
+
+public interface StatusService {
+
+ ApplicationStatus get(String serviceName, String serviceVersion);
+
+}
diff --git a/src/main/java/org/onap/nbi/apis/status/StatusServiceImpl.java b/src/main/java/org/onap/nbi/apis/status/StatusServiceImpl.java
new file mode 100644
index 0000000..7262aea
--- /dev/null
+++ b/src/main/java/org/onap/nbi/apis/status/StatusServiceImpl.java
@@ -0,0 +1,28 @@
+package org.onap.nbi.apis.status;
+
+import org.onap.nbi.apis.status.model.ApplicationStatus;
+import org.onap.nbi.apis.status.model.StatusType;
+import org.springframework.stereotype.Service;
+
+@Service("statusService")
+public class StatusServiceImpl implements StatusService {
+
+ @Override
+ public ApplicationStatus get(final String serviceName, final String serviceVersion) {
+
+ final boolean applicationIsUp = true;
+
+
+ final ApplicationStatus applicationStatus =
+ new ApplicationStatus(serviceName, (applicationIsUp ? StatusType.OK : StatusType.KO), serviceVersion);
+
+
+ return applicationStatus;
+ }
+
+
+ public boolean serviceIsUp() {
+ return true;
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/apis/status/model/ApplicationStatus.java b/src/main/java/org/onap/nbi/apis/status/model/ApplicationStatus.java
new file mode 100644
index 0000000..ecaa89e
--- /dev/null
+++ b/src/main/java/org/onap/nbi/apis/status/model/ApplicationStatus.java
@@ -0,0 +1,55 @@
+package org.onap.nbi.apis.status.model;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.onap.nbi.commons.Resource;
+
+public class ApplicationStatus implements Resource {
+
+ private String name;
+
+ private StatusType status;
+
+ private String version;
+
+ private Set<ApplicationStatus> components = new HashSet<>();
+
+ /**
+ * Builds a new {@code ApplicationStatus} with the following attributes :
+ *
+ * @param name name of the service
+ * @param state state of the service ({@code OK} | {@code KO})
+ * @param version version of the service ({@code x.y.z})
+ */
+ public ApplicationStatus(final String name, final StatusType status, final String version) {
+ this.name = name;
+ this.status = status;
+ this.version = version;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public StatusType getStatus() {
+ return this.status;
+ }
+
+ public String getVersion() {
+ return this.version;
+ }
+
+ public Set<ApplicationStatus> getComponents() {
+ return this.components;
+ }
+
+ public ApplicationStatus component(final ApplicationStatus componentStatus) {
+ this.components.add(componentStatus);
+ return this;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+}
diff --git a/src/main/java/org/onap/nbi/apis/status/model/StatusType.java b/src/main/java/org/onap/nbi/apis/status/model/StatusType.java
new file mode 100644
index 0000000..a54dc50
--- /dev/null
+++ b/src/main/java/org/onap/nbi/apis/status/model/StatusType.java
@@ -0,0 +1,30 @@
+package org.onap.nbi.apis.status.model;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public enum StatusType {
+
+ OK("ok"), KO("ko");
+ private final String value;
+
+ StatusType(String v) {
+ this.value = v;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return this.value;
+ }
+
+ @JsonCreator
+ public static StatusType fromValue(String v) {
+ for (StatusType c : StatusType.values()) {
+ if (c.value.equals(v)) {
+ return c;
+ }
+ }
+ throw new IllegalArgumentException(v);
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/BeanUtils.java b/src/main/java/org/onap/nbi/commons/BeanUtils.java
new file mode 100644
index 0000000..1d14f12
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/BeanUtils.java
@@ -0,0 +1,39 @@
+package org.onap.nbi.commons;
+
+import org.apache.commons.beanutils.PropertyUtilsBean;
+
+/**
+ *
+ */
+public class BeanUtils {
+
+ private static final PropertyUtilsBean PUB = new PropertyUtilsBean();
+
+ /**
+ *
+ * @param bean
+ * @param name
+ * @return
+ */
+ public static Object getNestedProperty(Object bean, String name) {
+ try {
+ return BeanUtils.PUB.getNestedProperty(bean, name);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ *
+ * @param bean
+ * @param name
+ * @param value
+ */
+ public static void setNestedProperty(Object bean, String name, Object value) {
+ try {
+ BeanUtils.PUB.setNestedProperty(bean, name, value);
+ } catch (Exception ex) {
+ }
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/JacksonFilter.java b/src/main/java/org/onap/nbi/commons/JacksonFilter.java
new file mode 100644
index 0000000..bc173c3
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/JacksonFilter.java
@@ -0,0 +1,169 @@
+package org.onap.nbi.commons;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class JacksonFilter {
+
+ private final static List<String> SKIPPED_FIELDS = Arrays.asList("internalId");
+
+
+ public static <R> List<ObjectNode> createNodes(List<R> list, JsonRepresentation jsonRepresentation) {
+
+ Set<R> set;
+ if (list == null) {
+ set = new LinkedHashSet<>();
+ } else {
+ set = new LinkedHashSet<>(list);
+ }
+ return createNodes(set, jsonRepresentation);
+ }
+
+ public static <R> List<ObjectNode> createNodes(Collection<R> collection, JsonRepresentation jsonRepresentation) {
+ List<ObjectNode> nodeList = new ArrayList<>();
+ for (R element : collection) {
+ ObjectNode node = createNode(element, jsonRepresentation);
+ nodeList.add(node);
+ }
+ return nodeList;
+ }
+
+ public static <R> ObjectNode createNode(R bean, JsonRepresentation jsonRepresentation) {
+ ObjectMapper mapper = new ObjectMapper();
+ return JacksonFilter.createNode(mapper, bean, jsonRepresentation.getAttributes());
+ }
+
+ private static <R> ObjectNode createNode(ObjectMapper mapper, R bean, Set<String> names) {
+ // split fieldNames in 2 categories :
+ // simpleFields for simple property names with no '.'
+ // nestedFields for nested property names with a '.'
+ Set<String> simpleFields = new LinkedHashSet<String>();
+ MultiValueMap nestedFields = new LinkedMultiValueMap();
+ buildFields(names, simpleFields, nestedFields);
+
+ // create a simple node with only one level containing all simples
+ // properties
+ ObjectNode rootNode = JacksonFilter.createNodeWithSimpleFields(mapper, bean, simpleFields);
+
+ // create nested nodes with deeper levels
+ Set<Map.Entry<String, List<String>>> entrySet = nestedFields.entrySet();
+ // for each nested value, create recursively a node
+ for (Map.Entry<String, List<String>> entry : entrySet) {
+ String rootFieldName = entry.getKey();
+ // add in current node only if full value is not already present in
+ // 1st level
+ if (!simpleFields.contains(rootFieldName)) {
+ Object nestedBean = BeanUtils.getNestedProperty(bean, rootFieldName);
+ // add only non null fields
+ if (nestedBean == null) {
+ continue;
+ }
+ Set<String> nestedFieldNames = new LinkedHashSet<String>(entry.getValue());
+ // current node is an array or a list
+ if ((nestedBean.getClass().isArray()) || (Collection.class.isAssignableFrom(nestedBean.getClass()))) {
+ handleListNode(mapper, rootNode, rootFieldName, nestedBean, nestedFieldNames);
+ } else {
+ // create recursively a node and add it in current root node
+ createNodeRecursively(mapper, rootNode, rootFieldName, nestedBean, nestedFieldNames);
+ }
+ }
+ }
+ return rootNode;
+ }
+
+ private static void createNodeRecursively(ObjectMapper mapper, ObjectNode rootNode, String rootFieldName,
+ Object nestedBean, Set<String> nestedFieldNames) {
+ ObjectNode nestedNode = JacksonFilter.createNode(mapper, nestedBean, nestedFieldNames);
+ if ((nestedNode != null) && (nestedNode.size() > 0)) {
+ rootNode.set(rootFieldName, nestedNode);
+ }
+ }
+
+ private static void buildFields(Set<String> names, Set<String> simpleFields, MultiValueMap nestedFields) {
+ for (String name : names) {
+ int index = name.indexOf('.');
+ boolean isNestedField = (index > 0) && (index < name.length());
+ if (isNestedField) {
+ String rootFieldName = name.substring(0, index);
+ String subFieldName = name.substring(index + 1);
+ nestedFields.add(rootFieldName, subFieldName);
+ } else {
+ simpleFields.add(name);
+ }
+ }
+ }
+
+ private static void handleListNode(ObjectMapper mapper, ObjectNode rootNode, String rootFieldName,
+ Object nestedBean, Set<String> nestedFieldNames) {
+ Object[] array = null;
+ if ((nestedBean.getClass().isArray())) {
+ array = (Object[]) nestedBean;
+ } else {
+ Collection<?> collection = (Collection<?>) nestedBean;
+ array = collection.toArray();
+ }
+ if (array.length > 0) {
+ // create a node for each element in array
+ // and add created node in an arrayNode
+ Collection<JsonNode> nodes = new LinkedList<JsonNode>();
+ for (Object object : array) {
+ ObjectNode nestedNode = JacksonFilter.createNode(mapper, object, nestedFieldNames);
+ if ((nestedNode != null) && (nestedNode.size() > 0)) {
+ nodes.add(nestedNode);
+ }
+ }
+ ArrayNode arrayNode = mapper.createArrayNode();
+ arrayNode.addAll(nodes);
+ if (arrayNode.size() > 0) {
+ rootNode.set(rootFieldName, arrayNode);
+ }
+ }
+ }
+
+ private static <R> ObjectNode createNodeWithSimpleFields(ObjectMapper mapper, R bean, Set<String> names) {
+ ObjectNode node = mapper.createObjectNode();
+ for (String name : names) {
+ // Prevent getting value of some fields
+ if (SKIPPED_FIELDS.contains(name)) {
+ continue;
+ }
+
+ JacksonFilter.nodePut(node, name, BeanUtils.getNestedProperty(bean, name));
+ }
+ return node;
+ }
+
+ private static void nodePut(ObjectNode node, String name, Object value) {
+ if (value instanceof Boolean) {
+ node.put(name, (Boolean) value);
+ } else if (value instanceof Integer) {
+ node.put(name, (Integer) value);
+ } else if (value instanceof Long) {
+ node.put(name, (Long) value);
+ } else if (value instanceof Float) {
+ node.put(name, (Float) value);
+ } else if (value instanceof Double) {
+ node.put(name, (Double) value);
+ } else if (value instanceof BigDecimal) {
+ node.put(name, (BigDecimal) value);
+ } else if (value instanceof String) {
+ node.put(name, (String) value);
+ } else {
+ node.putPOJO(name, value);
+ }
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/JsonRepresentation.java b/src/main/java/org/onap/nbi/commons/JsonRepresentation.java
new file mode 100644
index 0000000..0c71262
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/JsonRepresentation.java
@@ -0,0 +1,35 @@
+package org.onap.nbi.commons;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.springframework.util.MultiValueMap;
+
+public class JsonRepresentation {
+
+ private Set<String> attributes = new LinkedHashSet<>();
+
+ public JsonRepresentation() {}
+
+ public JsonRepresentation(MultiValueMap<String, String> queryParameters) {
+ this.attributes = QueryParserUtils.getFields(queryParameters);
+ }
+
+ public JsonRepresentation(Set<String> attributes) {
+ this.attributes.addAll(attributes);
+ }
+
+ public JsonRepresentation add(String attributePath) {
+ this.attributes.add(attributePath);
+ return this;
+ }
+
+ public JsonRepresentation add(JsonRepresentation jsonRepresentation) {
+ this.attributes.addAll(jsonRepresentation.getAttributes());
+ return this;
+ }
+
+ public Set<String> getAttributes() {
+ return attributes;
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/Query.java b/src/main/java/org/onap/nbi/commons/Query.java
new file mode 100644
index 0000000..8ee453f
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/Query.java
@@ -0,0 +1,26 @@
+package org.onap.nbi.commons;
+
+import org.springframework.util.MultiValueMap;
+
+
+
+public class Query {
+
+ private MultiValueMap<String, String> parameters;
+
+ private JsonRepresentation jsonRepresentation;
+
+ public Query(MultiValueMap<String, String> queryParameters) {
+ this.parameters = queryParameters;
+ this.jsonRepresentation = new JsonRepresentation(queryParameters);
+ }
+
+ public MultiValueMap<String, String> getParameters() {
+ return parameters;
+ }
+
+ public JsonRepresentation getRepresentation() {
+ return jsonRepresentation;
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/QueryParserUtils.java b/src/main/java/org/onap/nbi/commons/QueryParserUtils.java
new file mode 100644
index 0000000..69c32df
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/QueryParserUtils.java
@@ -0,0 +1,65 @@
+package org.onap.nbi.commons;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+/**
+ *
+ */
+public class QueryParserUtils {
+
+ private QueryParserUtils() {}
+
+ /**
+ *
+ * @param queryParameters
+ * @return
+ */
+ public static Set<String> getFields(MultiValueMap<String, String> queryParameters) {
+
+ Set<String> fieldSet = new HashSet<>();
+ if (queryParameters != null) {
+ // search for "all" parameter
+ if (queryParameters.containsKey(ReservedKeys.ALL_FIELDS)) {
+ queryParameters.remove(ReservedKeys.ALL_FIELDS);
+ fieldSet.add(ReservedKeys.ALL_FIELDS);
+ }
+ // search for "fields" parameters
+ List<String> queryParameterField =
+ queryParameters.remove(ReservedKeys.QUERY_KEY_FIELD_ESCAPE + ReservedKeys.QUERY_KEY_FIELD);
+ if (queryParameterField == null) {
+ queryParameterField = queryParameters.remove(ReservedKeys.QUERY_KEY_FIELD);
+ }
+ if (queryParameterField != null && !queryParameterField.isEmpty()) {
+ String queryParameterValue = queryParameterField.get(0);
+ if (queryParameterValue != null) {
+ String[] tokenArray = queryParameterValue.split(",");
+ fieldSet.addAll(Arrays.asList(tokenArray));
+ }
+ }
+ }
+ return fieldSet;
+ }
+
+ public static MultiValueMap<String, String> popCriteria(MultiValueMap<String, String> queryParameters) {
+
+ Set<Entry<String, List<String>>> entrySet = queryParameters.entrySet();
+
+ MultiValueMap<String, String> criterias = new LinkedMultiValueMap<String, String>();
+
+ entrySet.stream().forEach(entry -> {
+ final List<String> tempValues = new ArrayList<String>();
+ entry.getValue().stream().forEach(value -> tempValues.addAll(Arrays.asList(value.split(","))));
+ criterias.put(entry.getKey(), tempValues);
+ });
+
+ return criterias;
+ }
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/ReservedKeys.java b/src/main/java/org/onap/nbi/commons/ReservedKeys.java
new file mode 100644
index 0000000..dad59f2
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/ReservedKeys.java
@@ -0,0 +1,18 @@
+package org.onap.nbi.commons;
+
+/**
+ *
+ */
+public class ReservedKeys {
+
+ public static final String ALL_FIELDS = "all";
+
+ public static final String ID_FIELD = "id";
+
+ public static final String QUERY_KEY_FIELD = "fields";
+
+ public static final String QUERY_KEY_FIELD_ESCAPE = ":";
+
+ private ReservedKeys() {}
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/Resource.java b/src/main/java/org/onap/nbi/commons/Resource.java
new file mode 100644
index 0000000..4b374b0
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/Resource.java
@@ -0,0 +1,8 @@
+package org.onap.nbi.commons;
+
+
+public interface Resource {
+
+ public String getId();
+
+}
diff --git a/src/main/java/org/onap/nbi/commons/ResourceManagement.java b/src/main/java/org/onap/nbi/commons/ResourceManagement.java
new file mode 100644
index 0000000..67c0e3e
--- /dev/null
+++ b/src/main/java/org/onap/nbi/commons/ResourceManagement.java
@@ -0,0 +1,149 @@
+package org.onap.nbi.commons;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+
+public class ResourceManagement<T extends Resource> {
+
+ /**
+ * Build default 201 filtered response for resource
+ *
+ * @param resource
+ * @param jsonRepresentation
+ * @return
+ */
+ protected ResponseEntity<Object> createResponse(final Resource resource,
+ final JsonRepresentation jsonRepresentation) {
+
+ URI location = null;
+ if (RequestContextHolder.getRequestAttributes() != null) {
+ location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(resource.getId())
+ .toUri();
+ } else {
+ location = URI.create("/");
+ }
+
+
+ // Get entity representation
+ final Object entity = this.getEntity(resource, jsonRepresentation);
+
+ return ResponseEntity.created(location).body(entity);
+
+ }
+
+ /**
+ * Build default 200 filtered response for resource
+ *
+ * @param resource
+ * @param jsonRepresentation
+ * @return
+ */
+ protected ResponseEntity<Object> getResponse(final Object resource, final JsonRepresentation jsonRepresentation) {
+
+ // Get entity representation
+ final Object entity = this.getEntity(resource, jsonRepresentation);
+
+ return ResponseEntity.ok(entity);
+
+ }
+
+
+
+ /**
+ * Build default 206 filtered partial response for resource
+ *
+ * @param resource
+ * @param jsonRepresentation
+ * @return
+ */
+ protected ResponseEntity<Object> getPartialResponse(final Object resource,
+ final JsonRepresentation jsonRepresentation) {
+
+ // Get entity representation
+ final Object entity = this.getEntity(resource, jsonRepresentation);
+
+ return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT).body(entity);
+
+ }
+
+
+ /**
+ * Build default 200 filtered response for resource collection
+ *
+ * @param resources
+ * @param jsonRepresentation
+ * @param headers
+ * @return
+ */
+ protected ResponseEntity<Object> findResponse(final List<?> resources, final JsonRepresentation jsonRepresentation,
+ HttpHeaders headers) {
+
+ // Get entities representation
+ final Object entities = this.getEntities(resources, jsonRepresentation);
+
+ return ResponseEntity.ok().headers(headers).body(entities);
+
+ }
+
+
+ /**
+ * Build 204 Empty response
+ *
+ * @return
+ */
+ protected ResponseEntity<Object> deleteResponse() {
+
+ return ResponseEntity.noContent().build();
+ }
+
+ /**
+ * Get entity, as resource or jacksonNode depending fields value
+ *
+ * @param resource
+ * @param jsonRepresentation
+ * @return
+ */
+ protected Object getEntity(final Object resource, JsonRepresentation jsonRepresentation) {
+
+ Object entity;
+
+ Set<String> attributes = jsonRepresentation.getAttributes();
+
+ if (attributes == null || attributes.isEmpty() || attributes.contains(ReservedKeys.ALL_FIELDS)) {
+ entity = resource;
+ } else {
+ entity = JacksonFilter.createNode(resource, jsonRepresentation);
+ }
+
+ return entity;
+ }
+
+ /**
+ * Get entities, as resource list or jacksonNode depending fields value
+ *
+ * @param resources
+ * @param jsonRepresentation
+ * @return
+ */
+ protected Object getEntities(final List<?> resources, JsonRepresentation jsonRepresentation) {
+
+ Object entities;
+
+ Set<String> attributes = jsonRepresentation.getAttributes();
+
+ if (attributes == null || attributes.isEmpty() || attributes.contains(ReservedKeys.ALL_FIELDS)) {
+ entities = resources;
+ } else {
+ entities = JacksonFilter.createNodes(resources, jsonRepresentation);
+ }
+
+ return entities;
+ }
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..1d8ff27
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,6 @@
+# SERVER
+server.contextPath=/nbi/api/v1
+server.port = 8080
+
+# LOGGING
+logging.level.org.onap.nbi=WARN
diff --git a/src/test/java/org/onap/nbi/apis/status/StatusTest.java b/src/test/java/org/onap/nbi/apis/status/StatusTest.java
new file mode 100644
index 0000000..d262e15
--- /dev/null
+++ b/src/test/java/org/onap/nbi/apis/status/StatusTest.java
@@ -0,0 +1,41 @@
+package org.onap.nbi.apis.status;
+
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.test.context.junit4.SpringRunner;
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class StatusTest {
+
+ @Autowired
+ StatusResource statusResource;
+
+ private MockHttpServletRequest request;
+
+ @Before
+ public void setup() {
+ request = new MockHttpServletRequest();
+ request.setRequestURI("/nbi/api/v1/status");
+ }
+
+ @Test
+ public void testHealthCheck() {
+ ResponseEntity<Object> response = statusResource.status(request);
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ ObjectNode status = (ObjectNode) response.getBody();
+ assertThat(status.get("name").textValue()).isEqualTo("nbi");
+ assertThat(status.get("status").toString()).isEqualTo("OK");
+ assertThat(status.get("version").textValue()).isEqualTo("v1");
+ }
+}