api custom header 79/79079/9
authorluna <nil@vmware.com>
Mon, 25 Feb 2019 03:13:26 +0000 (11:13 +0800)
committerni lu <nil@vmware.com>
Fri, 15 Mar 2019 02:53:45 +0000 (02:53 +0000)
Issue-ID: DCAEGEN2-897

Change-Id: Iaff1a8f71a0ab1be997fbea654d6032eee91009b
Signed-off-by: luna <nil@vmware.com>
pom.xml
standardization/api-custom-header/pom.xml [new file with mode: 0644]
standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionManagement.java [new file with mode: 0644]
standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/ApiVersionModel.java [new file with mode: 0644]
standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtils.java [new file with mode: 0644]
standardization/api-custom-header/src/main/java/org/onap/dcaegen2/services/sdk/standardization/util/ObjectManagement.java [new file with mode: 0644]
standardization/api-custom-header/src/test/java/org/onap/dcaegen2/services/sdk/standardization/header/CustomHeaderUtilsTest.java [new file with mode: 0644]
standardization/api-custom-header/src/test/resources/api_version_config.json [new file with mode: 0644]
standardization/docs/custom_header.rst [new file with mode: 0644]
standardization/docs/index.rst [new file with mode: 0644]
standardization/pom.xml [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index 51ec777..28650dc 100644 (file)
--- 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>
       </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 (file)
index 0000000..6b00d06
--- /dev/null
@@ -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 (file)
index 0000000..06515dc
--- /dev/null
@@ -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 (file)
index 0000000..d3c09a2
--- /dev/null
@@ -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 (file)
index 0000000..ecd0831
--- /dev/null
@@ -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 (file)
index 0000000..3f173d3
--- /dev/null
@@ -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 (file)
index 0000000..73fcec1
--- /dev/null
@@ -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 (file)
index 0000000..81468ac
--- /dev/null
@@ -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 (file)
index 0000000..59014aa
--- /dev/null
@@ -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 (file)
index 0000000..33e2399
--- /dev/null
@@ -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 (file)
index 0000000..40d55d0
--- /dev/null
@@ -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