Change to use checked exceptions in rAPP Catalogue 95/5395/1
authorelinuxhenrik <henrik.b.andersson@est.tech>
Thu, 7 Jan 2021 14:42:31 +0000 (15:42 +0100)
committerelinuxhenrik <henrik.b.andersson@est.tech>
Thu, 7 Jan 2021 14:42:39 +0000 (15:42 +0100)
Add the parameter “unhandledException” with value “true” to the
generator to make the delegated implementation able to handle checked
exceptions.
Change the service's exceptions to be checked and adapt the code
accordingly.

Change-Id: I15cab337826b48d21ae83521d149f177d8dce00d
Issue-ID: NONRTRIC-373
Signed-off-by: elinuxhenrik <henrik.b.andersson@est.tech>
r-app-catalogue/pom.xml
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/GeneralRappCatalogueControllerAdvisor.java
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImpl.java
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/HeaderException.java
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/InvalidServiceException.java
r-app-catalogue/src/main/java/org/oransc/rappcatalogue/exception/ServiceNotFoundException.java
r-app-catalogue/src/test/java/org/oransc/rappcatalogue/api/ServicesApiDelegateImplTest.java

index a2e0565..0ceb7bb 100644 (file)
                             <invokerPackage>org.oransc.rappcatalogue</invokerPackage>\r
                             <configOptions>\r
                                 <delegatePattern>true</delegatePattern>\r
+                                <unhandledException>true</unhandledException>\r
                             </configOptions>\r
                         </configuration>\r
                     </execution>\r
index 939f7bf..072a5a0 100644 (file)
@@ -35,22 +35,19 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
 @ControllerAdvice
 public class GeneralRappCatalogueControllerAdvisor extends ResponseEntityExceptionHandler {
     @ExceptionHandler(InvalidServiceException.class)
-    public ResponseEntity<Object> handleInvalidServiceException(
-        InvalidServiceException ex) {
+    public ResponseEntity<Object> handleInvalidServiceException(InvalidServiceException ex) {
 
         return new ResponseEntity<>(getErrorInformation(ex, BAD_REQUEST), BAD_REQUEST);
     }
 
     @ExceptionHandler(ServiceNotFoundException.class)
-    public ResponseEntity<Object> handleServiceNotFoundException(
-        ServiceNotFoundException ex) {
+    public ResponseEntity<Object> handleServiceNotFoundException(ServiceNotFoundException ex) {
 
         return new ResponseEntity<>(getErrorInformation(ex, NOT_FOUND), NOT_FOUND);
     }
 
     @ExceptionHandler(HeaderException.class)
-    public ResponseEntity<Object> handleHeaderException(
-        HeaderException ex) {
+    public ResponseEntity<Object> handleHeaderException(HeaderException ex) {
 
         return new ResponseEntity<>(getErrorInformation(ex, INTERNAL_SERVER_ERROR), INTERNAL_SERVER_ERROR);
     }
index bb3a6dc..4615d69 100644 (file)
-/*-\r
- * ========================LICENSE_START=================================\r
- * Copyright (C) 2020 Nordix Foundation. All rights reserved.\r
- * ======================================================================\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- * ========================LICENSE_END===================================\r
- */\r
-\r
-package org.oransc.rappcatalogue.api;\r
-\r
-import java.io.IOException;\r
-import java.sql.Date;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-import java.util.Optional;\r
-import java.util.concurrent.ConcurrentHashMap;\r
-import javax.servlet.http.HttpServletRequest;\r
-import javax.servlet.http.HttpServletResponse;\r
-import org.oransc.rappcatalogue.exception.HeaderException;\r
-import org.oransc.rappcatalogue.exception.InvalidServiceException;\r
-import org.oransc.rappcatalogue.exception.ServiceNotFoundException;\r
-import org.oransc.rappcatalogue.model.InputService;\r
-import org.oransc.rappcatalogue.model.Service;\r
-import org.springframework.beans.factory.annotation.Autowired;\r
-import org.springframework.http.HttpStatus;\r
-import org.springframework.http.ResponseEntity;\r
-import org.springframework.web.context.request.NativeWebRequest;\r
-\r
-@org.springframework.stereotype.Service\r
-public class ServicesApiDelegateImpl implements ServicesApiDelegate {\r
-\r
-    private static final String LOCATION_HEADER = "Location";\r
-\r
-    @Autowired\r
-    private NativeWebRequest nativeWebRequest;\r
-\r
-    private ConcurrentHashMap<String, Service> registeredServices = new ConcurrentHashMap<>();\r
-\r
-    ServicesApiDelegateImpl(NativeWebRequest nativeWebRequest) {\r
-        this.nativeWebRequest = nativeWebRequest;\r
-    }\r
-\r
-    @Override\r
-    public Optional<NativeWebRequest> getRequest() {\r
-        return Optional.of(nativeWebRequest);\r
-    }\r
-\r
-    @Override\r
-    public ResponseEntity<Service> getIndividualService(String serviceName) {\r
-        Service service = registeredServices.get(serviceName);\r
-        if (service != null) {\r
-            return ResponseEntity.ok(service);\r
-        } else {\r
-            throw new ServiceNotFoundException(serviceName);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public ResponseEntity<List<Service>> getServices() {\r
-        return ResponseEntity.ok(new ArrayList<>(registeredServices.values()));\r
-    }\r
-\r
-    @Override\r
-    public ResponseEntity<Void> putIndividualService(String serviceName, InputService inputService) {\r
-        if (isServiceValid(inputService)) {\r
-            if (registeredServices.put(serviceName, createService(serviceName, inputService)) == null) {\r
-                try {\r
-                    getRequest().ifPresent(request -> addLocationHeaderToResponse(serviceName, request));\r
-                } catch (Exception e) {\r
-                    registeredServices.remove(serviceName);\r
-                    throw e;\r
-                }\r
-                return new ResponseEntity<>(HttpStatus.CREATED);\r
-            } else {\r
-                return new ResponseEntity<>(HttpStatus.OK);\r
-            }\r
-        } else {\r
-            throw new InvalidServiceException();\r
-        }\r
-    }\r
-\r
-    private void addLocationHeaderToResponse(String serviceName, NativeWebRequest request) {\r
-        try {\r
-            HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class);\r
-            HttpServletResponse nativeResponse = request.getNativeResponse(HttpServletResponse.class);\r
-            if (nativeRequest != null && nativeResponse != null) {\r
-                StringBuffer requestURL = nativeRequest.getRequestURL();\r
-                nativeResponse.addHeader(LOCATION_HEADER, requestURL.toString());\r
-                nativeResponse.getWriter().print("");\r
-            } else {\r
-                throw new HeaderException(LOCATION_HEADER, serviceName,\r
-                    new Exception("Native Request or Response missing"));\r
-            }\r
-        } catch (IOException e) {\r
-            throw new HeaderException(LOCATION_HEADER, serviceName, e);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public ResponseEntity<Void> deleteIndividualService(String serviceName) {\r
-        registeredServices.remove(serviceName);\r
-        return new ResponseEntity<>(HttpStatus.NO_CONTENT);\r
-    }\r
-\r
-    /*\r
-     * java:S2589: Boolean expressions should not be gratuitous.\r
-     * Even though the version property is marked as @NotNull, it might be null coming from the client, hence the null\r
-     * check is needed.\r
-     */\r
-    @SuppressWarnings("java:S2589")\r
-    private boolean isServiceValid(InputService service) {\r
-        String version = service.getVersion();\r
-        return version != null && !version.isBlank();\r
-    }\r
-\r
-    private Service createService(String serviceName, InputService inputService) {\r
-        Service service = new Service();\r
-        service.setName(serviceName);\r
-        service.setDescription(inputService.getDescription());\r
-        service.setDisplayName(inputService.getDisplayName());\r
-        service.setVersion(inputService.getVersion());\r
-        service.setRegistrationDate(getTodaysDate());\r
-        return service;\r
-    }\r
-\r
-    private String getTodaysDate() {\r
-        long millis = System.currentTimeMillis();\r
-        Date date = new Date(millis);\r
-        return date.toString();\r
-    }\r
-}\r
+/*-
+ * ========================LICENSE_START=================================
+ * Copyright (C) 2020 Nordix Foundation. 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.oransc.rappcatalogue.api;
+
+import java.io.IOException;
+import java.sql.Date;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.oransc.rappcatalogue.exception.HeaderException;
+import org.oransc.rappcatalogue.exception.InvalidServiceException;
+import org.oransc.rappcatalogue.exception.ServiceNotFoundException;
+import org.oransc.rappcatalogue.model.InputService;
+import org.oransc.rappcatalogue.model.Service;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.context.request.NativeWebRequest;
+
+@org.springframework.stereotype.Service
+public class ServicesApiDelegateImpl implements ServicesApiDelegate {
+
+    private static final String LOCATION_HEADER = "Location";
+
+    @Autowired
+    private NativeWebRequest nativeWebRequest;
+
+    private ConcurrentHashMap<String, Service> registeredServices = new ConcurrentHashMap<>();
+
+    ServicesApiDelegateImpl(NativeWebRequest nativeWebRequest) {
+        this.nativeWebRequest = nativeWebRequest;
+    }
+
+    @Override
+    public Optional<NativeWebRequest> getRequest() {
+        return Optional.of(nativeWebRequest);
+    }
+
+    @Override
+    public ResponseEntity<Service> getIndividualService(String serviceName) throws ServiceNotFoundException {
+        Service service = registeredServices.get(serviceName);
+        if (service != null) {
+            return ResponseEntity.ok(service);
+        } else {
+            throw new ServiceNotFoundException(serviceName);
+        }
+    }
+
+    @Override
+    public ResponseEntity<List<Service>> getServices() {
+        return ResponseEntity.ok(new ArrayList<>(registeredServices.values()));
+    }
+
+    @Override
+    public ResponseEntity<Void> putIndividualService(String serviceName, InputService inputService)
+        throws InvalidServiceException, HeaderException {
+        if (isServiceValid(inputService)) {
+            if (registeredServices.put(serviceName, createService(serviceName, inputService)) == null) {
+                try {
+                    Optional<NativeWebRequest> request = getRequest();
+                    if (request.isPresent()) {
+                        addLocationHeaderToResponse(serviceName, request.get());
+                    }
+                } catch (HeaderException e) {
+                    registeredServices.remove(serviceName);
+                    throw e;
+                }
+                return new ResponseEntity<>(HttpStatus.CREATED);
+            } else {
+                return new ResponseEntity<>(HttpStatus.OK);
+            }
+        } else {
+            throw new InvalidServiceException();
+        }
+    }
+
+    private void addLocationHeaderToResponse(String serviceName, NativeWebRequest request) throws HeaderException {
+        try {
+            HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class);
+            HttpServletResponse nativeResponse = request.getNativeResponse(HttpServletResponse.class);
+            if (nativeRequest != null && nativeResponse != null) {
+                StringBuffer requestURL = nativeRequest.getRequestURL();
+                nativeResponse.addHeader(LOCATION_HEADER, requestURL.toString());
+                nativeResponse.getWriter().print("");
+            } else {
+                throw new HeaderException(LOCATION_HEADER, serviceName,
+                    new Exception("Native Request or Response missing"));
+            }
+        } catch (IOException e) {
+            throw new HeaderException(LOCATION_HEADER, serviceName, e);
+        }
+    }
+
+    @Override
+    public ResponseEntity<Void> deleteIndividualService(String serviceName) {
+        registeredServices.remove(serviceName);
+        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+    }
+
+    /*
+     * java:S2589: Boolean expressions should not be gratuitous. Even though the
+     * version property is marked as @NotNull, it might be null coming from the
+     * client, hence the null check is needed.
+     */
+    @SuppressWarnings("java:S2589")
+    private boolean isServiceValid(InputService service) {
+        String version = service.getVersion();
+        return version != null && !version.isBlank();
+    }
+
+    private Service createService(String serviceName, InputService inputService) {
+        Service service = new Service();
+        service.setName(serviceName);
+        service.setDescription(inputService.getDescription());
+        service.setDisplayName(inputService.getDisplayName());
+        service.setVersion(inputService.getVersion());
+        service.setRegistrationDate(getTodaysDate());
+        return service;
+    }
+
+    private String getTodaysDate() {
+        long millis = System.currentTimeMillis();
+        Date date = new Date(millis);
+        return date.toString();
+    }
+}
index 676ae1c..8f64449 100644 (file)
@@ -18,7 +18,7 @@
 
 package org.oransc.rappcatalogue.exception;
 
-public class HeaderException extends RuntimeException {
+public class HeaderException extends Exception {
 
     private static final long serialVersionUID = -7798178963078284655L;
 
index dce815b..45ec769 100644 (file)
@@ -18,7 +18,7 @@
 
 package org.oransc.rappcatalogue.exception;
 
-public class InvalidServiceException extends RuntimeException {
+public class InvalidServiceException extends Exception {
     private static final long serialVersionUID = 3849219105170316564L;
 
     public InvalidServiceException() {
index 26b4b27..8411cf4 100644 (file)
@@ -18,7 +18,7 @@
 
 package org.oransc.rappcatalogue.exception;
 
-public class ServiceNotFoundException extends RuntimeException {
+public class ServiceNotFoundException extends Exception {
     private static final long serialVersionUID = 6579271315716003988L;
 
     public ServiceNotFoundException(String serviceName) {
index f2f30ff..dd10a65 100644 (file)
-package org.oransc.rappcatalogue.api;\r
-\r
-import static org.assertj.core.api.Assertions.assertThat;\r
-import static org.junit.jupiter.api.Assertions.assertThrows;\r
-import static org.mockito.Mockito.mock;\r
-import static org.mockito.Mockito.verify;\r
-import static org.mockito.Mockito.when;\r
-import static org.springframework.http.HttpStatus.CREATED;\r
-import static org.springframework.http.HttpStatus.NO_CONTENT;\r
-import static org.springframework.http.HttpStatus.OK;\r
-\r
-import java.io.IOException;\r
-import java.io.PrintWriter;\r
-import java.sql.Date;\r
-import java.util.Arrays;\r
-import java.util.List;\r
-import javax.servlet.http.HttpServletRequest;\r
-import javax.servlet.http.HttpServletResponse;\r
-import org.junit.jupiter.api.Test;\r
-import org.junit.jupiter.api.extension.ExtendWith;\r
-import org.mockito.Mock;\r
-import org.mockito.junit.jupiter.MockitoExtension;\r
-import org.oransc.rappcatalogue.exception.HeaderException;\r
-import org.oransc.rappcatalogue.exception.InvalidServiceException;\r
-import org.oransc.rappcatalogue.exception.ServiceNotFoundException;\r
-import org.oransc.rappcatalogue.model.InputService;\r
-import org.oransc.rappcatalogue.model.Service;\r
-import org.springframework.http.ResponseEntity;\r
-import org.springframework.web.context.request.NativeWebRequest;\r
-\r
-@ExtendWith(MockitoExtension.class)\r
-class ServicesApiDelegateImplTest {\r
-\r
-    @Mock\r
-    NativeWebRequest webRequestMock;\r
-\r
-    private static final String INVALID_SERVICE_MESSAGE = "Service is missing required property: version";\r
-    private static final String SERVICE_NAME = "Service Name";\r
-    private static final String SERVICE_DESCRIPTION = "description";\r
-    private static final String SERVICE_VERSION = "1.0";\r
-    private static final String SERVICE_DISPLAY_NAME = "Display Name";\r
-\r
-    @Test\r
-    void getAddedService_shouldReturnService() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
-\r
-        InputService service = new InputService();\r
-        service.setDescription(SERVICE_DESCRIPTION);\r
-        service.setVersion(SERVICE_VERSION);\r
-        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
-\r
-        whenPrintResponseShouldWork();\r
-\r
-        delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-\r
-        ResponseEntity<Service> response = delegateUnderTest.getIndividualService(SERVICE_NAME);\r
-\r
-        assertThat(response.getStatusCode()).isEqualTo(OK);\r
-        assertThat(response.getBody().getName()).isEqualTo(SERVICE_NAME);\r
-    }\r
-\r
-    @Test\r
-    void getMissingService_shouldThrowException() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);\r
-\r
-        Exception exception = assertThrows(ServiceNotFoundException.class, () -> {\r
-            delegateUnderTest.getIndividualService(SERVICE_NAME);\r
-        });\r
-\r
-        String expectedMessage = "Service " + SERVICE_NAME + " not found";\r
-        String actualMessage = exception.getMessage();\r
-\r
-        assertThat(actualMessage).isEqualTo(expectedMessage);\r
-    }\r
-\r
-    @Test\r
-    void putNewValidService_shouldBeCreatedAndRegisteredAndUrlToNewServiceAddedToLocationHeaderInResponse() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
-\r
-        InputService service = new InputService();\r
-        service.setDescription(SERVICE_DESCRIPTION);\r
-        service.setVersion(SERVICE_VERSION);\r
-        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
-\r
-        String urlToCreatedService = "URL to created Service";\r
-        HttpServletResponse servletResponseMock = whenPrintResponseShouldWork(urlToCreatedService);\r
-\r
-        ResponseEntity<Void> putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-\r
-        assertThat(putResponse.getStatusCode()).isEqualTo(CREATED);\r
-        verify(servletResponseMock).addHeader("Location", urlToCreatedService);\r
-\r
-        ResponseEntity<Service> getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME);\r
-\r
-        assertThat(getResponse.getStatusCode()).isEqualTo(OK);\r
-        Service body = getResponse.getBody();\r
-        assertThat(body.getName()).isEqualTo(SERVICE_NAME);\r
-        assertThat(body.getRegistrationDate()).isEqualTo(getTodaysDate());\r
-    }\r
-\r
-    @Test\r
-    void putModifiedService_shouldBeModified() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
-\r
-        InputService service = new InputService();\r
-        service.setDescription(SERVICE_DESCRIPTION);\r
-        service.setVersion(SERVICE_VERSION);\r
-        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
-\r
-        whenPrintResponseShouldWork();\r
-\r
-        delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-\r
-        String newDescription = "New description";\r
-        service.setDescription(newDescription);\r
-        ResponseEntity<Void> putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-\r
-        assertThat(putResponse.getStatusCode()).isEqualTo(OK);\r
-\r
-        ResponseEntity<Service> getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME);\r
-\r
-        assertThat(getResponse.getStatusCode()).isEqualTo(OK);\r
-        assertThat(getResponse.getBody().getDescription()).isEqualTo(newDescription);\r
-    }\r
-\r
-    @Test\r
-    void putServiceWithVersionNull_shouldThrowException() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);\r
-\r
-        InputService service = new InputService();\r
-        service.setDescription(SERVICE_DESCRIPTION);\r
-        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
-\r
-        Exception exception = assertThrows(InvalidServiceException.class, () -> {\r
-            delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-        });\r
-\r
-        assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE);\r
-    }\r
-\r
-    @Test\r
-    void putServiceWithBlankVersion_shouldThrowException() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);\r
-\r
-        InputService service = new InputService();\r
-        service.setVersion("");\r
-        service.setDescription(SERVICE_DESCRIPTION);\r
-        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
-\r
-        Exception exception = assertThrows(InvalidServiceException.class, () -> {\r
-            delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-        });\r
-\r
-        assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE);\r
-    }\r
-\r
-    @Test\r
-    void putServiceWhenIoExceptionAddingHeader_shouldThrowExceptionAndNoServiceCreated() throws Exception {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
-\r
-        whenGetRequestUrlThenReturnUrl();\r
-        HttpServletResponse servletResponseMock = mock(HttpServletResponse.class);\r
-        when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock);\r
-        when(servletResponseMock.getWriter()).thenThrow(new IOException("Error"));\r
-\r
-        InputService service = new InputService();\r
-        service.setVersion("1.0");\r
-        service.setDescription(SERVICE_DESCRIPTION);\r
-        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
-\r
-        Exception exception = assertThrows(HeaderException.class, () -> {\r
-            delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-        });\r
-\r
-        assertThat(exception.getMessage())\r
-            .isEqualTo("Unable to set header Location in put response for service " + SERVICE_NAME + ". Cause: Error");\r
-\r
-        ResponseEntity<List<Service>> response = delegateUnderTest.getServices();\r
-        assertThat(response.getBody()).isEmpty();\r
-    }\r
-\r
-    @Test\r
-    void getServices_shouldProvideArrayOfAddedServiceNames() throws Exception {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
-\r
-        InputService service1 = new InputService();\r
-        service1.setDescription("description 1");\r
-        service1.setVersion(SERVICE_VERSION);\r
-        service1.setDisplayName("Display Name 1");\r
-\r
-        InputService service2 = new InputService();\r
-        service2.setDescription("description 2");\r
-        service2.setVersion(SERVICE_VERSION);\r
-        service2.setDisplayName("Display Name 2");\r
-\r
-        whenPrintResponseShouldWork();\r
-\r
-        String serviceName1 = "Service Name 1";\r
-        delegateUnderTest.putIndividualService(serviceName1, service1);\r
-        String serviceName2 = "Service Name 2";\r
-        delegateUnderTest.putIndividualService(serviceName2, service2);\r
-\r
-        ResponseEntity<List<Service>> response = delegateUnderTest.getServices();\r
-\r
-        assertThat(response.getStatusCode()).isEqualTo(OK);\r
-        List<Service> services = response.getBody();\r
-        assertThat(services).hasSize(2);\r
-        List<String> expectedServiceNames = Arrays.asList(serviceName1, serviceName2);\r
-        assertThat(expectedServiceNames).contains(services.get(0).getName()) //\r
-            .contains(services.get(1).getName());\r
-    }\r
-\r
-    @Test\r
-    void deleteService_shouldBeOk() {\r
-        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);\r
-\r
-        InputService service = new InputService();\r
-        service.setDescription(SERVICE_DESCRIPTION);\r
-        service.setVersion(SERVICE_VERSION);\r
-        service.setDisplayName(SERVICE_DISPLAY_NAME);\r
-\r
-        whenPrintResponseShouldWork();\r
-\r
-        delegateUnderTest.putIndividualService(SERVICE_NAME, service);\r
-\r
-        ResponseEntity<List<Service>> servicesResponse = delegateUnderTest.getServices();\r
-\r
-        assertThat(servicesResponse.getBody()).hasSize(1);\r
-\r
-        ResponseEntity<Void> deleteResponse = delegateUnderTest.deleteIndividualService(SERVICE_NAME);\r
-\r
-        assertThat(deleteResponse.getStatusCode()).isEqualTo(NO_CONTENT);\r
-\r
-        servicesResponse = delegateUnderTest.getServices();\r
-\r
-        assertThat(servicesResponse.getBody()).isEmpty();\r
-    }\r
-\r
-    private void whenGetRequestUrlThenReturnUrl() {\r
-        whenGetRequestUrlThenReturnUrl("URL");\r
-    }\r
-\r
-    private void whenGetRequestUrlThenReturnUrl(String url) {\r
-        HttpServletRequest servletRequestMock = mock(HttpServletRequest.class);\r
-        when(webRequestMock.getNativeRequest(HttpServletRequest.class)).thenReturn(servletRequestMock);\r
-        when(servletRequestMock.getRequestURL()).thenReturn(new StringBuffer(url));\r
-    }\r
-\r
-    private HttpServletResponse whenPrintResponseShouldWork() {\r
-        return whenPrintResponseShouldWork("URL");\r
-    }\r
-\r
-    private HttpServletResponse whenPrintResponseShouldWork(String url) {\r
-        whenGetRequestUrlThenReturnUrl(url);\r
-        HttpServletResponse servletResponseMock = mock(HttpServletResponse.class);\r
-        when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock);\r
-        PrintWriter printWriterMock = mock(PrintWriter.class);\r
-        try {\r
-            when(servletResponseMock.getWriter()).thenReturn(printWriterMock);\r
-        } catch (IOException e) {\r
-            // Nothing\r
-        }\r
-        return servletResponseMock;\r
-    }\r
-\r
-    private String getTodaysDate() {\r
-        long millis = System.currentTimeMillis();\r
-        Date date = new Date(millis);\r
-        return date.toString();\r
-    }\r
-}\r
+
+package org.oransc.rappcatalogue.api;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.http.HttpStatus.CREATED;
+import static org.springframework.http.HttpStatus.NO_CONTENT;
+import static org.springframework.http.HttpStatus.OK;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.Date;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.oransc.rappcatalogue.exception.HeaderException;
+import org.oransc.rappcatalogue.exception.InvalidServiceException;
+import org.oransc.rappcatalogue.exception.ServiceNotFoundException;
+import org.oransc.rappcatalogue.model.InputService;
+import org.oransc.rappcatalogue.model.Service;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.context.request.NativeWebRequest;
+
+@ExtendWith(MockitoExtension.class)
+class ServicesApiDelegateImplTest {
+
+    @Mock
+    NativeWebRequest webRequestMock;
+
+    private static final String INVALID_SERVICE_MESSAGE = "Service is missing required property: version";
+    private static final String SERVICE_NAME = "Service Name";
+    private static final String SERVICE_DESCRIPTION = "description";
+    private static final String SERVICE_VERSION = "1.0";
+    private static final String SERVICE_DISPLAY_NAME = "Display Name";
+
+    @Test
+    void getAddedService_shouldReturnService() throws Exception {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);
+
+        InputService service = new InputService();
+        service.setDescription(SERVICE_DESCRIPTION);
+        service.setVersion(SERVICE_VERSION);
+        service.setDisplayName(SERVICE_DISPLAY_NAME);
+
+        whenPrintResponseShouldWork();
+
+        delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+
+        ResponseEntity<Service> response = delegateUnderTest.getIndividualService(SERVICE_NAME);
+
+        assertThat(response.getStatusCode()).isEqualTo(OK);
+        assertThat(response.getBody().getName()).isEqualTo(SERVICE_NAME);
+    }
+
+    @Test
+    void getMissingService_shouldThrowException() {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);
+
+        Exception exception = assertThrows(ServiceNotFoundException.class, () -> {
+            delegateUnderTest.getIndividualService(SERVICE_NAME);
+        });
+
+        String expectedMessage = "Service " + SERVICE_NAME + " not found";
+        String actualMessage = exception.getMessage();
+
+        assertThat(actualMessage).isEqualTo(expectedMessage);
+    }
+
+    @Test
+    void putNewValidService_shouldBeCreatedAndRegisteredAndUrlToNewServiceAddedToLocationHeaderInResponse()
+        throws Exception {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);
+
+        InputService service = new InputService();
+        service.setDescription(SERVICE_DESCRIPTION);
+        service.setVersion(SERVICE_VERSION);
+        service.setDisplayName(SERVICE_DISPLAY_NAME);
+
+        String urlToCreatedService = "URL to created Service";
+        HttpServletResponse servletResponseMock = whenPrintResponseShouldWork(urlToCreatedService);
+
+        ResponseEntity<Void> putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+
+        assertThat(putResponse.getStatusCode()).isEqualTo(CREATED);
+        verify(servletResponseMock).addHeader("Location", urlToCreatedService);
+
+        ResponseEntity<Service> getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME);
+
+        assertThat(getResponse.getStatusCode()).isEqualTo(OK);
+        Service body = getResponse.getBody();
+        assertThat(body.getName()).isEqualTo(SERVICE_NAME);
+        assertThat(body.getRegistrationDate()).isEqualTo(getTodaysDate());
+    }
+
+    @Test
+    void putModifiedService_shouldBeModified() throws Exception {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);
+
+        InputService service = new InputService();
+        service.setDescription(SERVICE_DESCRIPTION);
+        service.setVersion(SERVICE_VERSION);
+        service.setDisplayName(SERVICE_DISPLAY_NAME);
+
+        whenPrintResponseShouldWork();
+
+        delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+
+        String newDescription = "New description";
+        service.setDescription(newDescription);
+        ResponseEntity<Void> putResponse = delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+
+        assertThat(putResponse.getStatusCode()).isEqualTo(OK);
+
+        ResponseEntity<Service> getResponse = delegateUnderTest.getIndividualService(SERVICE_NAME);
+
+        assertThat(getResponse.getStatusCode()).isEqualTo(OK);
+        assertThat(getResponse.getBody().getDescription()).isEqualTo(newDescription);
+    }
+
+    @Test
+    void putServiceWithVersionNull_shouldThrowException() {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);
+
+        InputService service = new InputService();
+        service.setDescription(SERVICE_DESCRIPTION);
+        service.setDisplayName(SERVICE_DISPLAY_NAME);
+
+        Exception exception = assertThrows(InvalidServiceException.class, () -> {
+            delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+        });
+
+        assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE);
+    }
+
+    @Test
+    void putServiceWithBlankVersion_shouldThrowException() {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(null);
+
+        InputService service = new InputService();
+        service.setVersion("");
+        service.setDescription(SERVICE_DESCRIPTION);
+        service.setDisplayName(SERVICE_DISPLAY_NAME);
+
+        Exception exception = assertThrows(InvalidServiceException.class, () -> {
+            delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+        });
+
+        assertThat(exception.getMessage()).isEqualTo(INVALID_SERVICE_MESSAGE);
+    }
+
+    @Test
+    void putServiceWhenIoExceptionAddingHeader_shouldThrowExceptionAndNoServiceCreated() throws Exception {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);
+
+        whenGetRequestUrlThenReturnUrl();
+        HttpServletResponse servletResponseMock = mock(HttpServletResponse.class);
+        when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock);
+        when(servletResponseMock.getWriter()).thenThrow(new IOException("Error"));
+
+        InputService service = new InputService();
+        service.setVersion("1.0");
+        service.setDescription(SERVICE_DESCRIPTION);
+        service.setDisplayName(SERVICE_DISPLAY_NAME);
+
+        Exception exception = assertThrows(HeaderException.class, () -> {
+            delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+        });
+
+        assertThat(exception.getMessage())
+            .isEqualTo("Unable to set header Location in put response for service " + SERVICE_NAME + ". Cause: Error");
+
+        ResponseEntity<List<Service>> response = delegateUnderTest.getServices();
+        assertThat(response.getBody()).isEmpty();
+    }
+
+    @Test
+    void getServices_shouldProvideArrayOfAddedServiceNames() throws Exception {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);
+
+        InputService service1 = new InputService();
+        service1.setDescription("description 1");
+        service1.setVersion(SERVICE_VERSION);
+        service1.setDisplayName("Display Name 1");
+
+        InputService service2 = new InputService();
+        service2.setDescription("description 2");
+        service2.setVersion(SERVICE_VERSION);
+        service2.setDisplayName("Display Name 2");
+
+        whenPrintResponseShouldWork();
+
+        String serviceName1 = "Service Name 1";
+        delegateUnderTest.putIndividualService(serviceName1, service1);
+        String serviceName2 = "Service Name 2";
+        delegateUnderTest.putIndividualService(serviceName2, service2);
+
+        ResponseEntity<List<Service>> response = delegateUnderTest.getServices();
+
+        assertThat(response.getStatusCode()).isEqualTo(OK);
+        List<Service> services = response.getBody();
+        assertThat(services).hasSize(2);
+        List<String> expectedServiceNames = Arrays.asList(serviceName1, serviceName2);
+        assertThat(expectedServiceNames).contains(services.get(0).getName()) //
+            .contains(services.get(1).getName());
+    }
+
+    @Test
+    void deleteService_shouldBeOk() throws Exception {
+        ServicesApiDelegateImpl delegateUnderTest = new ServicesApiDelegateImpl(webRequestMock);
+
+        InputService service = new InputService();
+        service.setDescription(SERVICE_DESCRIPTION);
+        service.setVersion(SERVICE_VERSION);
+        service.setDisplayName(SERVICE_DISPLAY_NAME);
+
+        whenPrintResponseShouldWork();
+
+        delegateUnderTest.putIndividualService(SERVICE_NAME, service);
+
+        ResponseEntity<List<Service>> servicesResponse = delegateUnderTest.getServices();
+
+        assertThat(servicesResponse.getBody()).hasSize(1);
+
+        ResponseEntity<Void> deleteResponse = delegateUnderTest.deleteIndividualService(SERVICE_NAME);
+
+        assertThat(deleteResponse.getStatusCode()).isEqualTo(NO_CONTENT);
+
+        servicesResponse = delegateUnderTest.getServices();
+
+        assertThat(servicesResponse.getBody()).isEmpty();
+    }
+
+    private void whenGetRequestUrlThenReturnUrl() {
+        whenGetRequestUrlThenReturnUrl("URL");
+    }
+
+    private void whenGetRequestUrlThenReturnUrl(String url) {
+        HttpServletRequest servletRequestMock = mock(HttpServletRequest.class);
+        when(webRequestMock.getNativeRequest(HttpServletRequest.class)).thenReturn(servletRequestMock);
+        when(servletRequestMock.getRequestURL()).thenReturn(new StringBuffer(url));
+    }
+
+    private HttpServletResponse whenPrintResponseShouldWork() {
+        return whenPrintResponseShouldWork("URL");
+    }
+
+    private HttpServletResponse whenPrintResponseShouldWork(String url) {
+        whenGetRequestUrlThenReturnUrl(url);
+        HttpServletResponse servletResponseMock = mock(HttpServletResponse.class);
+        when(webRequestMock.getNativeResponse(HttpServletResponse.class)).thenReturn(servletResponseMock);
+        PrintWriter printWriterMock = mock(PrintWriter.class);
+        try {
+            when(servletResponseMock.getWriter()).thenReturn(printWriterMock);
+        } catch (IOException e) {
+            // Nothing
+        }
+        return servletResponseMock;
+    }
+
+    private String getTodaysDate() {
+        long millis = System.currentTimeMillis();
+        Date date = new Date(millis);
+        return date.toString();
+    }
+}