diff options
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 @@ -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"); + } +} |