summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pom.xml8
-rw-r--r--standardization/api-custom-header/pom.xml45
-rw-r--r--standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionManagement.java141
-rw-r--r--standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionModel.java53
-rw-r--r--standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtils.java222
-rw-r--r--standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/util/ObjectManagement.java53
-rw-r--r--standardization/api-custom-header/src/test/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtilsTest.java75
-rw-r--r--standardization/api-custom-header/src/test/resources/api_version_config.json7
-rw-r--r--standardization/docs/custom_header.rst86
-rw-r--r--standardization/docs/index.rst11
-rw-r--r--standardization/pom.xml26
11 files changed, 723 insertions, 4 deletions
diff --git a/pom.xml b/pom.xml
index 51ec777c..28650dcf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,5 @@
-<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/maven-v4_0_0.xsd">
+<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onap.oparent</groupId>
@@ -46,6 +45,7 @@
<module>rest-services</module>
<module>services</module>
<module>security</module>
+ <module>standardization</module>
</modules>
<build>
@@ -228,4 +228,4 @@
</dependency>
</dependencies>
</dependencyManagement>
-</project>
+</project> \ No newline at end of file
diff --git a/standardization/api-custom-header/pom.xml b/standardization/api-custom-header/pom.xml
new file mode 100644
index 00000000..6b00d06c
--- /dev/null
+++ b/standardization/api-custom-header/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onap.dcaegen2.services.sdk</groupId>
+ <artifactId>dcaegen2-services-sdk-standardization</artifactId>
+ <version>1.1.3-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <groupId>org.onap.dcaegen2.services.sdk.standardization</groupId>
+ <artifactId>api-custom-header</artifactId>
+ <name>api-custom-header</name>
+ <packaging>jar</packaging>
+
+ <properties>
+ <java.version>8</java.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.8.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jetbrains</groupId>
+ <artifactId>annotations</artifactId>
+ </dependency>
+ <!-- TESTING -->
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionManagement.java b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionManagement.java
new file mode 100644
index 00000000..06515dca
--- /dev/null
+++ b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionManagement.java
@@ -0,0 +1,141 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.services.sdk
+ * ================================================================================
+ * Copyright (C) 2019 vmware. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dcaegen2.services.sdk.standardization.header;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.onap.dcaegen2.services.sdk.standardization.util.ObjectManagement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.google.gson.Gson;
+
+public final class ApiVersionManagement {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ApiVersionManagement.class);
+ private static final Object INSTANCE = new Object();
+ private static final String API_VERSION = "apiVersion";
+
+ private static Map<String, List<ApiVersionModel>> verModelMap;
+
+ /**
+ * private constructor
+ */
+ private ApiVersionManagement() {
+
+ }
+
+ /**
+ * get api version from json string
+ *
+ * @param apiFilePath api file path
+ * @param requestedApiName current api name
+ * @return all api version for a major version
+ */
+ public static List<ApiVersionModel> getApiVersion(String apiFilePath, String requestedApiName) {
+ if (null != verModelMap) {
+ List<ApiVersionModel> apiLst = verModelMap.get(requestedApiName);
+ return ObjectManagement.isCollectionEmpty(apiLst) ? Collections.emptyList()
+ : Collections.unmodifiableList(apiLst);
+ }
+
+ synchronized (INSTANCE) {
+ if (null == verModelMap) {
+ verModelMap = new HashMap<>();
+ String apiVerJsonStr = readApiVersions(apiFilePath);
+
+ // component not pass the apiversion parameter
+ if (apiVerJsonStr.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ // read service or resource api and put in HashMap one by one.
+ convertVerToModel(parseApiVersion(apiVerJsonStr));
+ }
+ }
+
+ List<ApiVersionModel> apiLst = verModelMap.get(requestedApiName);
+ return ObjectManagement.isCollectionEmpty(apiLst) ? Collections.emptyList()
+ : Collections.unmodifiableList(verModelMap.get(requestedApiName));
+ }
+
+ /**
+ * parse api versions from api json string
+ *
+ * @param apiVerJsonStr all api versions in json format
+ * @return api versions<apikey, List<version>> in map format
+ */
+ private static Map<String, Object> parseApiVersion(String apiVerJsonStr) {
+ Map<String, Object> apiMap = new Gson().fromJson(apiVerJsonStr, Map.class);
+ if (apiMap.containsKey(API_VERSION)) {
+ return apiMap;
+ }
+
+ // there is no apiVersion filed in apiVerJsonStr or the format is wrong.
+ LOGGER.error("the struct of api version is wrong, so return the empty api map.");
+ return Collections.emptyMap();
+ }
+
+ /**
+ * convert api version into ApiVersionModel object
+ *
+ * @param apiMap Map object for all api versions
+ */
+ private static void convertVerToModel(Map<String, Object> apiMap) {
+ if (apiMap.isEmpty()) {
+ verModelMap = Collections.emptyMap();
+ return;
+ }
+
+ List<Object> currApiArray = null;
+ Map<String, Object> apiVersMap = (apiMap.get(API_VERSION) instanceof Map) ? (Map) apiMap.get(API_VERSION) : null;
+ if (null != apiVersMap) {
+ for (Map.Entry<String, Object> entry : apiVersMap.entrySet()) {
+ currApiArray = (entry.getValue() instanceof List) ? (List) entry.getValue() : null;
+ if (null != currApiArray) {
+ List<ApiVersionModel> currApiLst = new ArrayList<>();
+ currApiArray.forEach(currApi -> currApiLst.add(new ApiVersionModel(currApi.toString())));
+ verModelMap.put(entry.getKey(), currApiLst);
+ }
+ }
+ }
+ }
+
+ /**
+ * read api version from path
+ *
+ * @param filePath api versions
+ * @return api versions json string
+ */
+ private static String readApiVersions(String filePath) {
+ try {
+ return new String(Files.readAllBytes(Paths.get(filePath)));
+ } catch (IOException e) {
+ LOGGER.error("Fail to read api version file", e);
+ }
+
+ return "";
+ }
+} \ No newline at end of file
diff --git a/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionModel.java b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionModel.java
new file mode 100644
index 00000000..d3c09a2b
--- /dev/null
+++ b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionModel.java
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.services.sdk
+ * ================================================================================
+ * Copyright (C) 2019 vmware. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dcaegen2.services.sdk.standardization.header;
+
+public class ApiVersionModel {
+ private String majorVersion;
+ private String minorVersion;
+ private String patchVersion;
+ private String version;
+
+ public ApiVersionModel(String version) {
+ this.version = version;
+ if (null != version) {
+ String[] verArray = version.split("\\.");
+ majorVersion = verArray[0];
+ minorVersion = verArray.length > 1 ? verArray[1] : null;
+ patchVersion = verArray.length > 2 ? verArray[2] : null;
+ }
+ }
+
+ public String getMajorVersion() {
+ return majorVersion;
+ }
+
+ public String getMinorVersion() {
+ return minorVersion;
+ }
+
+ public String getPatchVersion() {
+ return patchVersion;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+} \ No newline at end of file
diff --git a/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtils.java b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtils.java
new file mode 100644
index 00000000..ecd08314
--- /dev/null
+++ b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtils.java
@@ -0,0 +1,222 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.services.sdk
+ * ================================================================================
+ * Copyright (C) 2019 vmware. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dcaegen2.services.sdk.standardization.header;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+import org.onap.dcaegen2.services.sdk.standardization.util.ObjectManagement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CustomHeaderUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(CustomHeaderUtils.class);
+
+ /**
+ * more detail:
+ * https://wiki.onap.org/display/DW/ONAP+API+Common+Versioning+Strategy+%28CVS%29+Guidelines
+ */
+ private static final String API_MINOR_VERSION = "X-MinorVersion";
+ private static final String API_PATCH_VERSION = "X-PatchVersion";
+ private static final String API_LATEST_VERSION = "X-LatestVersion";
+
+ /**
+ * identify whether validate minor version successfully
+ */
+ private static final ThreadLocal<Boolean> CLIENT_MINOR_VERSION_OK = new ThreadLocal<>();
+ private String majorVersion = null;
+ private String minorVersion = null;
+ private List<ApiVersionModel> verLst = null;
+
+ /**
+ * construct
+ *
+ * @param requestMajorVer client request major version
+ * @param reqHeaderMap request headers
+ * @param apiFilePath api file path
+ * @param requestedApiName api name that is requested by client
+ *
+ */
+ public CustomHeaderUtils(@NotNull String requestMajorVer, @NotNull Map<String, String> reqHeaderMap,
+ @NotNull String apiFilePath, @NotNull String requestedApiName) {
+ // all api versions
+ if (!requestedApiName.isEmpty()) {
+ verLst = ApiVersionManagement.getApiVersion(apiFilePath, requestedApiName);
+ }
+
+ // major version that client requests
+ this.majorVersion = requestMajorVer;
+
+ // minor version that client requests
+ this.minorVersion = reqHeaderMap.get(API_MINOR_VERSION);
+
+ CLIENT_MINOR_VERSION_OK.set(Boolean.TRUE);
+ }
+
+ /**
+ * get the custom headers of response
+ *
+ * @return rspHeader custom headers of response
+ */
+ public Map<String, String> getRspCustomHeader() {
+ try {
+ return calCustomHeader();
+ } finally {
+ CLIENT_MINOR_VERSION_OK.remove();
+ }
+ }
+
+ /**
+ * calculate the custom header for response
+ *
+ * @return rspHeader custom headers of response
+ */
+ private Map<String, String> calCustomHeader() {
+ if (ObjectManagement.isCollectionEmpty(this.verLst)) {
+ logger.warn("there is no api version configured in server.");
+ return new HashMap<>();
+ }
+
+ // if client not send X-MinorVersion, return the first minor version that major version is requested
+ if (ObjectManagement.isStringEmpty(this.minorVersion)) {
+ return calHeadersNoMinorVer();
+ }
+
+ // if client send x-MinorVersion, minor vefrsion is wrong
+ if (!CLIENT_MINOR_VERSION_OK.get()) {
+ return calHeadersWithWrongMinorVer();
+ }
+
+ // client send X-MinorVersion and minor version is right
+ return calHeadersWithMinorVer();
+ }
+
+ /**
+ * calculate the custom header should be returned when client send minor version which is wrong
+ *
+ * @return rspHeader custom headers of response
+ */
+ private Map<String, String> calHeadersWithWrongMinorVer() {
+ Map<String, String> rspHeader = new HashMap<>(3);
+
+ // Latest version mean greatest version
+ rspHeader.put(API_LATEST_VERSION, this.verLst.get(verLst.size() - 1).getVersion());
+
+ ApiVersionModel currVer = null;
+ for (int index = 0; index < this.verLst.size(); index++) {
+ if (this.majorVersion.equals(this.verLst.get(index).getMajorVersion())) {
+ currVer = this.verLst.get(index);
+ } else {
+ if (null != currVer) {
+ break;
+ }
+ }
+ }
+
+ if (null == currVer) {
+ logger.warn("wrong apiVersiona are provided, major {} not foud in them", this.majorVersion);
+ } else {
+ rspHeader.put(API_MINOR_VERSION, currVer.getMinorVersion());
+ rspHeader.put(API_PATCH_VERSION, currVer.getPatchVersion());
+ }
+
+ return rspHeader;
+ }
+
+ /**
+ * calculate the custom header should be returned when client send minor version which is right
+ *
+ * @return rspHeader custom headers of response
+ */
+ private Map<String, String> calHeadersWithMinorVer() {
+ Map<String, String> rspHeader = new HashMap<>(3);
+
+ // Latest version mean greatest version
+ rspHeader.put(API_LATEST_VERSION, this.verLst.get(verLst.size() - 1).getVersion());
+
+ // set minor version
+ rspHeader.put(API_MINOR_VERSION, this.minorVersion);
+
+ // set patch version
+ ApiVersionModel currVer = null;
+ for (int index = 0; index < this.verLst.size(); index++) {
+ currVer = verLst.get(index);
+ if (this.majorVersion.equals(currVer.getMajorVersion()) && this.minorVersion.equals(currVer.getMinorVersion())) {
+ rspHeader.put(API_PATCH_VERSION, currVer.getPatchVersion());
+ break;
+ }
+ }
+
+ return rspHeader;
+ }
+
+ /**
+ * calculate the custom header should be returned when client not send minor version
+ *
+ * @return rspHeader custom headers of response
+ */
+ private Map<String, String> calHeadersNoMinorVer() {
+ Map<String, String> rspHeader = new HashMap<>(3);
+
+ // Latest version mean greatest version
+ rspHeader.put(API_LATEST_VERSION, this.verLst.get(verLst.size() - 1).getVersion());
+
+ // the first version of major version
+ ApiVersionModel currVer = null;
+ for (int index = 0; index < this.verLst.size(); index++) {
+ currVer = verLst.get(index);
+ if (this.majorVersion.equals(currVer.getMajorVersion())) {
+ rspHeader.put(API_MINOR_VERSION, currVer.getMinorVersion());
+ rspHeader.put(API_PATCH_VERSION, currVer.getPatchVersion());
+ break;
+ }
+ }
+
+ return rspHeader;
+ }
+
+ /**
+ * Check header whether it is right.
+ *
+ * @return true when validating successfully or minor version not exist
+ */
+ public boolean isOkCustomHeaders() {
+ if (ObjectManagement.isStringEmpty(this.minorVersion)) {
+ logger.warn("X-MinorVersion is empty or null");
+ return true;
+ }
+
+ ApiVersionModel currVer = null;
+
+ // verList is an order array, which is from the first version to the latest version.
+ for (int index = 0; index < this.verLst.size(); index++) {
+ currVer = verLst.get(index);
+ if (currVer.getMajorVersion().equals(this.majorVersion) && currVer.getMinorVersion().equals(this.minorVersion)) {
+ return true;
+ }
+ }
+
+ logger.error("not find major version {} and minor version {}", this.majorVersion, this.minorVersion);
+ CLIENT_MINOR_VERSION_OK.set(Boolean.FALSE);
+ return false;
+ }
+} \ No newline at end of file
diff --git a/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/util/ObjectManagement.java b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/util/ObjectManagement.java
new file mode 100644
index 00000000..3f173d31
--- /dev/null
+++ b/standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/util/ObjectManagement.java
@@ -0,0 +1,53 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.services.sdk
+ * ================================================================================
+ * Copyright (C) 2019 vmware. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dcaegen2.services.sdk.standardization.util;
+
+
+import java.util.Collection;
+
+public final class ObjectManagement {
+
+ /**
+ * constructor that not permit to new object
+ */
+ private ObjectManagement() {
+
+ }
+
+ /**
+ * check string object if it is empty
+ *
+ * @param str string object
+ * @return true when str is null or empty
+ */
+ public static boolean isStringEmpty(String str) {
+ return null == str || str.isEmpty();
+ }
+
+ /**
+ * check collection object if it is empty
+ *
+ * @param c collection object
+ * @return true when c is null or empty
+ */
+ public static boolean isCollectionEmpty(Collection<?> c) {
+ return null == c || c.isEmpty();
+ }
+} \ No newline at end of file
diff --git a/standardization/api-custom-header/src/test/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtilsTest.java b/standardization/api-custom-header/src/test/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtilsTest.java
new file mode 100644
index 00000000..73fcec1a
--- /dev/null
+++ b/standardization/api-custom-header/src/test/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtilsTest.java
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcaegen2.services.sdk
+ * ================================================================================
+ * Copyright (C) 2019 vmware. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dcaegen2.services.sdk.standardization.header;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class CustomHeaderUtilsTest {
+ private String filePath = getClass().getClassLoader().getResource("api_version_config.json").getPath();
+
+ /**
+ * not send minor version when client requests
+ */
+ @Test
+ void testRequestNoMinorVer() {
+ CustomHeaderUtils util = getHeaderUtil(null);
+ util.isOkCustomHeaders();
+
+ Map<String, String> rspHeaders = util.getRspCustomHeader();
+ Assertions.assertTrue("3".equals(rspHeaders.get("X-MinorVersion")));
+ }
+
+ /**
+ * minor version not exist which client request
+ */
+ @Test
+ void testRequestWithWrongMinorVer() {
+ CustomHeaderUtils util = getHeaderUtil("2");
+
+ // check request header
+ util.isOkCustomHeaders();
+
+ Assertions.assertFalse(util.isOkCustomHeaders());
+
+ Map<String, String> rspHeaders = util.getRspCustomHeader();
+ Assertions.assertTrue("4".equals(rspHeaders.get("X-MinorVersion")));
+ }
+
+ /**
+ * minor version exists which client request
+ */
+ @Test
+ void testRequestWithMinorVerOk() {
+ CustomHeaderUtils util = getHeaderUtil("3");
+ Assertions.assertFalse(!util.isOkCustomHeaders());
+
+ Map<String, String> rspHeaders = util.getRspCustomHeader();
+ Assertions.assertTrue("3".equals(rspHeaders.get("X-MinorVersion")));
+ }
+
+ private CustomHeaderUtils getHeaderUtil(String minorVer) {
+ Map<String, String> reqHeaderMap = new HashMap<String, String>();
+ reqHeaderMap.put("X-MinorVersion", minorVer);
+ return new CustomHeaderUtils("5", reqHeaderMap, filePath, "eventListener");
+ }
+} \ No newline at end of file
diff --git a/standardization/api-custom-header/src/test/resources/api_version_config.json b/standardization/api-custom-header/src/test/resources/api_version_config.json
new file mode 100644
index 00000000..81468ac4
--- /dev/null
+++ b/standardization/api-custom-header/src/test/resources/api_version_config.json
@@ -0,0 +1,7 @@
+{
+ "apiVersion":
+ {
+ "eventListener": ["4.7.2","5.3.2","5.4.1","7.0.1"],
+ "xxxxxx": ["1.0.2","1.1.2","2.0.1"]
+ }
+} \ No newline at end of file
diff --git a/standardization/docs/custom_header.rst b/standardization/docs/custom_header.rst
new file mode 100644
index 00000000..59014aa4
--- /dev/null
+++ b/standardization/docs/custom_header.rst
@@ -0,0 +1,86 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright 2019 vmware
+
+1. Background
+=============
+
+Trouble shooting and tell client the latest api version under that major version is requested.
+
+2. Propose
+==========
+
+https://wiki.onap.org/display/DW/ONAP+API+Common+Versioning+Strategy+%28CVS%29+Guidelines
+
+3. HLD
+======
+
+3.1 Version Management
+----------------------
+
+Every component provides a json file or property configuration which is used to describe the api version detail. The example of json file content as:
+{
+"apiVersion":
+{
+"eventListener":["4.7.2","5.3.2","5.4.1","7.0.1"],
+"xxxxxx": ["1.0.2","1.1.2","2.0.1"]
+}
+}
+
+============== ============== =====================================================================================================================================================================================================================================
+**Field** **Value type** **remark**
+apiVersion Map An identify that start to describe the api versions
+eventListener Array<String> A service, resource or function name of component, which is a unique identify of one api. Requirement: describe the api version in sequence that is from first version to greatest version.
+============== ============== =====================================================================================================================================================================================================================================
+
+In the future, if there are other version configurations which need to be described, extend other fields.
+
+3.2 Return response with custom headers
+---------------------------------------
+
+First, server should check the custom header of client, if X-MinorVersion does not exist which is maybe deletes after a period time or that client requests is wrong because of some reason, return response with errorcode 400 and the first major version including X-MinorVersion, X-PatchVersion, X-LatestVersion.
+
+3.2.1 Minor version non-exist
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For exmpale, ves has no 5.2.x version, so if the request of client is major version v5, X-MinorVersion is 2, the server return with 400 errorcode and custom headers including X-MinorVersion 4, X-PatchVersion 1, X-LatestVersion 5.4.1
+
+=========================== ================== ================== ================== =================== ======================================================================================================================================
+**Client send** **Server return**
+=========================== ================== ================== ================== =================== ======================================================================================================================================
+**major version requested** **X-MinorVersion** **X-MinorVersion** **X-PatchVersion** **X-LatestVersion** **remark**
+v5 2 4 1 7.0.1 Fail to valid, return 400. X-MinorVersion and x-patchversion are under the last version that the major version is requested by client.
+=========================== ================== ================== ================== =================== ======================================================================================================================================
+
+3.2.2 Minor version exist
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+=========================== ================== ================== ================== =================== =====================================================
+**Client send** **Server return**
+=========================== ================== ================== ================== =================== =====================================================
+**major version requested** **X-MinorVersion** **X-MinorVersion** **X-PatchVersion** **X-LatestVersion** **remark**
+v5 no 3 2 7.0.1 Supported request; X-MinorVersion and x-patchversion are under the first version that the major
+v5 4 4 1 7.0.1 Valid request; respond with customer header
+v5 3 3 2 7.0.1 Valid request; respond with customer header
+v7 no 0 1 7.0.1 Supported request; notify client with customer header
+v7 0 0 1 7.0.1 Supported request; notify client with customer header
+=========================== ================== ================== ================== =================== =====================================================
+
+3.3 Code Implement
+------------------
+
+CustomHeaderUtils is a class that provides functions to validate the X-MinorVersion which client requests and return the response header according to the client request.
+
+The usage example:
+------------------
+CustomHeaderUtils util = new CustomHeaderUtils(requestMajorVer, reqHeaderMap, filePath, "eventListener");
+
+
+// check request header
+
+util.isOkCustomHeaders();
+
+
+// get response header
+
+Map<String, String> rspHeader = util.getRspCustomHeader() \ No newline at end of file
diff --git a/standardization/docs/index.rst b/standardization/docs/index.rst
new file mode 100644
index 00000000..33e23991
--- /dev/null
+++ b/standardization/docs/index.rst
@@ -0,0 +1,11 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright 2019 vmware
+
+ONAP API Standardization
+========================================
+
+.. toctree::
+ :maxdepth: 1
+
+ custom_header.rst \ No newline at end of file
diff --git a/standardization/pom.xml b/standardization/pom.xml
new file mode 100644
index 00000000..40d55d06
--- /dev/null
+++ b/standardization/pom.xml
@@ -0,0 +1,26 @@
+<?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>
+
+ <parent>
+ <groupId>org.onap.dcaegen2.services</groupId>
+ <artifactId>sdk</artifactId>
+ <version>1.1.3-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <groupId>org.onap.dcaegen2.services.sdk</groupId>
+ <artifactId>dcaegen2-services-sdk-standardization</artifactId>
+
+ <name>dcaegen2-services-sdk-standardization</name>
+ <description>Common SDK repo for all DCAE standardization</description>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>api-custom-header</module>
+ </modules>
+
+</project> \ No newline at end of file