From 25da75eacf48856824dd4e89b7ebd0da68fdef8a Mon Sep 17 00:00:00 2001 From: MatthieuGeerebaert Date: Mon, 26 Mar 2018 17:08:28 +0200 Subject: Add initial sources - Springboot application - Apache license 2.0 - Healthcheck Change-Id: I0dedfbe3348195f7be00ec8d27fbf25dfcda52b0 Issue-ID: EXTAPI-36 Signed-off-by: MatthieuGeerebaert --- .gitignore | 127 ++++++++++++++++ LICENSE.txt | 7 + README.md | 7 + pom.xml | 86 +++++++++++ src/main/java/org/onap/nbi/Application.java | 13 ++ .../org/onap/nbi/apis/status/StatusResource.java | 55 +++++++ .../org/onap/nbi/apis/status/StatusService.java | 9 ++ .../onap/nbi/apis/status/StatusServiceImpl.java | 28 ++++ .../nbi/apis/status/model/ApplicationStatus.java | 55 +++++++ .../org/onap/nbi/apis/status/model/StatusType.java | 30 ++++ src/main/java/org/onap/nbi/commons/BeanUtils.java | 39 +++++ .../java/org/onap/nbi/commons/JacksonFilter.java | 169 +++++++++++++++++++++ .../org/onap/nbi/commons/JsonRepresentation.java | 35 +++++ src/main/java/org/onap/nbi/commons/Query.java | 26 ++++ .../org/onap/nbi/commons/QueryParserUtils.java | 65 ++++++++ .../java/org/onap/nbi/commons/ReservedKeys.java | 18 +++ src/main/java/org/onap/nbi/commons/Resource.java | 8 + .../org/onap/nbi/commons/ResourceManagement.java | 149 ++++++++++++++++++ src/main/resources/application.properties | 6 + .../java/org/onap/nbi/apis/status/StatusTest.java | 41 +++++ 20 files changed, 973 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/org/onap/nbi/Application.java create mode 100644 src/main/java/org/onap/nbi/apis/status/StatusResource.java create mode 100644 src/main/java/org/onap/nbi/apis/status/StatusService.java create mode 100644 src/main/java/org/onap/nbi/apis/status/StatusServiceImpl.java create mode 100644 src/main/java/org/onap/nbi/apis/status/model/ApplicationStatus.java create mode 100644 src/main/java/org/onap/nbi/apis/status/model/StatusType.java create mode 100644 src/main/java/org/onap/nbi/commons/BeanUtils.java create mode 100644 src/main/java/org/onap/nbi/commons/JacksonFilter.java create mode 100644 src/main/java/org/onap/nbi/commons/JsonRepresentation.java create mode 100644 src/main/java/org/onap/nbi/commons/Query.java create mode 100644 src/main/java/org/onap/nbi/commons/QueryParserUtils.java create mode 100644 src/main/java/org/onap/nbi/commons/ReservedKeys.java create mode 100644 src/main/java/org/onap/nbi/commons/Resource.java create mode 100644 src/main/java/org/onap/nbi/commons/ResourceManagement.java create mode 100644 src/main/resources/application.properties create mode 100644 src/test/java/org/onap/nbi/apis/status/StatusTest.java 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 @@ + + + 4.0.0 + + org.onap.nbi + nbi-rest-services + 1.0.0-SNAPSHOT + jar + + nbi-rest-services + + + org.springframework.boot + spring-boot-starter-parent + 1.5.10.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + Apache2 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.apache.commons + commons-io + 1.3.2 + + + + commons-beanutils + commons-beanutils + 1.9.3 + + + + org.apache.commons + commons-lang3 + 3.4 + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-devtools + runtime + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + 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 { + + @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 status(HttpServletRequest request) { + + ResponseEntity 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 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 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 SKIPPED_FIELDS = Arrays.asList("internalId"); + + + public static List createNodes(List list, JsonRepresentation jsonRepresentation) { + + Set set; + if (list == null) { + set = new LinkedHashSet<>(); + } else { + set = new LinkedHashSet<>(list); + } + return createNodes(set, jsonRepresentation); + } + + public static List createNodes(Collection collection, JsonRepresentation jsonRepresentation) { + List nodeList = new ArrayList<>(); + for (R element : collection) { + ObjectNode node = createNode(element, jsonRepresentation); + nodeList.add(node); + } + return nodeList; + } + + public static ObjectNode createNode(R bean, JsonRepresentation jsonRepresentation) { + ObjectMapper mapper = new ObjectMapper(); + return JacksonFilter.createNode(mapper, bean, jsonRepresentation.getAttributes()); + } + + private static ObjectNode createNode(ObjectMapper mapper, R bean, Set names) { + // split fieldNames in 2 categories : + // simpleFields for simple property names with no '.' + // nestedFields for nested property names with a '.' + Set simpleFields = new LinkedHashSet(); + 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>> entrySet = nestedFields.entrySet(); + // for each nested value, create recursively a node + for (Map.Entry> 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 nestedFieldNames = new LinkedHashSet(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 nestedFieldNames) { + ObjectNode nestedNode = JacksonFilter.createNode(mapper, nestedBean, nestedFieldNames); + if ((nestedNode != null) && (nestedNode.size() > 0)) { + rootNode.set(rootFieldName, nestedNode); + } + } + + private static void buildFields(Set names, Set 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 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 nodes = new LinkedList(); + 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 ObjectNode createNodeWithSimpleFields(ObjectMapper mapper, R bean, Set 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 attributes = new LinkedHashSet<>(); + + public JsonRepresentation() {} + + public JsonRepresentation(MultiValueMap queryParameters) { + this.attributes = QueryParserUtils.getFields(queryParameters); + } + + public JsonRepresentation(Set 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 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 parameters; + + private JsonRepresentation jsonRepresentation; + + public Query(MultiValueMap queryParameters) { + this.parameters = queryParameters; + this.jsonRepresentation = new JsonRepresentation(queryParameters); + } + + public MultiValueMap 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 getFields(MultiValueMap queryParameters) { + + Set 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 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 popCriteria(MultiValueMap queryParameters) { + + Set>> entrySet = queryParameters.entrySet(); + + MultiValueMap criterias = new LinkedMultiValueMap(); + + entrySet.stream().forEach(entry -> { + final List tempValues = new ArrayList(); + 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 { + + /** + * Build default 201 filtered response for resource + * + * @param resource + * @param jsonRepresentation + * @return + */ + protected ResponseEntity 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 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 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 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 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 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 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 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"); + } +} -- cgit 1.2.3-korg