Commit c107569f authored by femiadeyemi's avatar femiadeyemi
Browse files

improve code quality and fix some minor bugs

Motivation:

This is to improve cerebrum code.

Modification:

- remove the workaround inside CerebrumConfig by using
    SslContextFactory.Client
- create a utility class for the controllers and move all
    common methods into this class.
- use the correct helmholtz aai uri inside the MarketUserController
- supress some some methods warnings
- make the deleteUuid inside the MarketServiceRepository to
    return Long type
- remove the public modifier of the OrganizationControllerTest and
    CerebrumExceptionHandlerTest. Also the public modifier for
    the tests were remove in other Cerebrum code can conform
    with Sonar recommended code quality.

Result:

Minor bug fixes with improve code quality and readility. No
visible changes to the user.

Target: master
parent 937ce44b
......@@ -32,3 +32,7 @@ build/
### VS Code ###
.vscode/
# CI
.gitlab
.gitlab-ci.yml
\ No newline at end of file
......@@ -10,7 +10,8 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
public class HelmholtzCerebrumApplication
{
public static void main(String[] args) {
public static void main(String[] args)
{
SpringApplication.run(HelmholtzCerebrumApplication.class, args);
}
}
\ No newline at end of file
......@@ -14,13 +14,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
public class CerebrumConfig
{
/**
* FIXME: This is workaround for the Internal Server Error
* org.springframework.web.util.NestedServletException:
* Request processing failed; nested exception is
* java.lang.NullPointerException: Missing SslContextFactory
*/
private final SslContextFactory ssl = new SslContextFactory();
private final SslContextFactory.Client ssl = new SslContextFactory.Client();
private final HttpClient httpClient = new HttpClient(ssl);
ClientHttpConnector clientConnector = new JettyClientHttpConnector(httpClient);
......
package de.helmholtz.marketplace.cerebrum.config;
import de.helmholtz.marketplace.cerebrum.repository.listeners.MarketUserEventHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CerebrumRepositoryConfig
{
public CerebrumRepositoryConfig() {
super();
}
@Bean
MarketUserEventHandler makeUserEventHandler() {
return new MarketUserEventHandler();
}
}
......@@ -10,6 +10,7 @@ import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.Collections;
import static org.springframework.security.config.Customizer.withDefaults;
......@@ -32,7 +33,7 @@ public class CerebrumSecurityConfig extends WebSecurityConfigurerAdapter
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("${cerebrum.allowed.client.origins}"));
configuration.setAllowedOrigins(Collections.singletonList("${cerebrum.allowed.client.origins}"));
configuration.setAllowedMethods(Arrays.asList("GET","DELETE","PUT","POST"));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
......
package de.helmholtz.marketplace.cerebrum.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fge.jsonpatch.JsonPatch;
import com.github.fge.jsonpatch.JsonPatchException;
import io.swagger.v3.oas.annotations.Operation;
......@@ -33,13 +31,12 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import de.helmholtz.marketplace.cerebrum.entities.MarketService;
import de.helmholtz.marketplace.cerebrum.errorhandling.exception.CerebrumEntityNotFoundException;
import de.helmholtz.marketplace.cerebrum.repository.MarketServiceRepository;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities;
@RestController
@RequestMapping(path = "${spring.data.rest.base-path}/services", produces = MediaType.APPLICATION_JSON_VALUE)
......@@ -72,7 +69,7 @@ public class MarketServiceController {
@RequestParam(value = "sort", defaultValue = "name.asc") List<String> sorts)
{
return marketServiceRepository.findAll(
PageRequest.of(page, size, Sort.by(getOrders(sorts))));
PageRequest.of(page, size, Sort.by(CerebrumControllerUtilities.getOrders(sorts))));
}
/* get single Service */
......@@ -153,7 +150,8 @@ public class MarketServiceController {
return marketServiceRepository.findByUuid(uuid)
.map(marketService -> {
try {
MarketService marketServicePatched = applyPatchToMarketService(patch, marketService);
MarketService marketServicePatched =
CerebrumControllerUtilities.applyPatch(patch, marketService, MarketService.class);
return marketServiceRepository.save(marketServicePatched);
} catch (JsonPatchException e) {
throw new ResponseStatusException(
......@@ -183,33 +181,4 @@ public class MarketServiceController {
marketServiceRepository.deleteByUuid(uuid);
return ResponseEntity.noContent().build();
}
/**
* TODO: util methods - it might be better to factor these out
*/
private MarketService applyPatchToMarketService(
JsonPatch patch,
MarketService targetMarketService) throws JsonPatchException, JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode patched = patch.apply(objectMapper.convertValue(targetMarketService, JsonNode.class));
return objectMapper.treeToValue(patched, MarketService.class);
}
private List<Sort.Order> getOrders(List<String> sorts)
{
List<Sort.Order> orders = new ArrayList<>();
for (String sort: sorts) {
if (sort.contains(".")) {
String[] order = sort.split("\\.");
orders.add(new Sort.Order(
order[1].equals("asc") ?
Sort.Direction.ASC :
Sort.Direction.DESC, order[0])
);
} else {
orders.add(new Sort.Order(Sort.Direction.ASC, sort));
}
}
return orders;
}
}
......@@ -7,8 +7,8 @@ import de.helmholtz.marketplace.cerebrum.entities.MarketUser;
import de.helmholtz.marketplace.cerebrum.errorhandling.CerebrumApiError;
import de.helmholtz.marketplace.cerebrum.errorhandling.exception.CerebrumEntityNotFoundException;
import de.helmholtz.marketplace.cerebrum.repository.MarketUserRepository;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fge.jsonpatch.JsonPatch;
import com.github.fge.jsonpatch.JsonPatchException;
import io.swagger.v3.oas.annotations.Operation;
......@@ -80,12 +80,13 @@ public class MarketUserController {
public JsonNode whoami() {
return this.authorisationServer
.get()
.uri("https://login.helmholtz-data-federation.de/oauth2/userinfo")
.uri("https://login.helmholtz.de/oauth2/userinfo")
.retrieve()
.bodyToMono(JsonNode.class)
.block();
}
@SuppressWarnings("unused")
public boolean isSomebody(JwtAuthenticationToken token) {
if (Objects.isNull(token)) return false;
String name = marketUserRepository.findBySub((String) token.getTokenAttributes().get("sub")).getFirstName();
......@@ -214,7 +215,8 @@ public class MarketUserController {
return marketUserRepository.findByUuid(uuid)
.map(marketUser -> {
try {
MarketUser marketUserPatched = applyPatchToMarketUser(patch, marketUser);
MarketUser marketUserPatched =
CerebrumControllerUtilities.applyPatch(patch, marketUser, MarketUser.class);
marketUser.setEmail(marketUserPatched.getEmail());
marketUser.setFirstName(marketUserPatched.getFirstName());
marketUser.setLastName(marketUserPatched.getLastName());
......@@ -255,14 +257,4 @@ public class MarketUserController {
throw new CerebrumEntityNotFoundException("user", uuid);
}
}
/* for MarketUser - PATCH */
private MarketUser applyPatchToMarketUser(
JsonPatch patch,
MarketUser targetMarketUser) throws JsonPatchException, JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode patched = patch.apply(objectMapper.convertValue(targetMarketUser, JsonNode.class));
return objectMapper.treeToValue(patched, MarketUser.class);
}
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ import de.helmholtz.marketplace.cerebrum.errorhandling.CerebrumApiError;
import de.helmholtz.marketplace.cerebrum.errorhandling.exception.CerebrumEntityNotFoundException;
import de.helmholtz.marketplace.cerebrum.errorhandling.exception.CerebrumInvalidUuidException;
import de.helmholtz.marketplace.cerebrum.repository.OrganizationRepository;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumControllerUtilities;
import de.helmholtz.marketplace.cerebrum.utils.CerebrumEntityUuidGenerator;
import io.swagger.v3.oas.annotations.Operation;
......@@ -17,8 +18,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fge.jsonpatch.JsonPatch;
import com.github.fge.jsonpatch.JsonPatchException;
import org.springframework.data.domain.PageRequest;
......@@ -45,7 +44,6 @@ import org.springframework.web.util.UriComponentsBuilder;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
......@@ -85,7 +83,7 @@ public class OrganizationController {
@RequestParam(value = "sort", defaultValue = "name.asc") List<String> sorts)
{
return organizationRepository.findAll(
PageRequest.of(page, size, Sort.by(getOrders(sorts))));
PageRequest.of(page, size, Sort.by(CerebrumControllerUtilities.getOrders(sorts))));
}
/* get Organization */
......@@ -218,7 +216,8 @@ public class OrganizationController {
Organization partialUpdateOrganisation = organizationRepository.findByUuid(uuid)
.map(organization -> {
try {
Organization organizationPatched = applyPatchToOrganization(patch, organization);
Organization organizationPatched =
CerebrumControllerUtilities.applyPatch(patch, organization, Organization.class);
return organizationRepository.save(organizationPatched);
} catch (JsonPatchException e) {
throw new ResponseStatusException(
......@@ -253,33 +252,4 @@ public class OrganizationController {
organizationRepository.deleteByUuid(uuid);
return ResponseEntity.noContent().build();
}
/**
* TODO: util methods - it might be better to factor these out
*/
private Organization applyPatchToOrganization(
JsonPatch patch,
Organization targetOrganization) throws JsonPatchException, JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode patched = patch.apply(objectMapper.convertValue(targetOrganization, JsonNode.class));
return objectMapper.treeToValue(patched, Organization.class);
}
private List<Sort.Order> getOrders(List<String> sorts)
{
List<Sort.Order> orders = new ArrayList<>();
for (String sort: sorts) {
if (sort.contains(".")) {
String[] order = sort.split("\\.");
orders.add(new Sort.Order(
order[1].equals("asc") ?
Sort.Direction.ASC :
Sort.Direction.DESC, order[0])
);
} else {
orders.add(new Sort.Order(Sort.Direction.ASC, sort));
}
}
return orders;
}
}
......@@ -33,8 +33,7 @@ public class MarketUser
@Size(max = 100)
private String lastName;
@Schema(description = "User chosen name to represent him or herself",
example = "pm", required = false)
@Schema(description = "User chosen name to represent him or herself", example = "pm")
@Size(max = 20)
private String screenName;
......
......@@ -10,5 +10,6 @@ public interface MarketServiceRepository extends PagingAndSortingRepository<Mark
{
Optional<MarketService> findByUuid(String uuid);
void deleteByUuid(String id);
@SuppressWarnings("UnusedReturnValue")
Long deleteByUuid(String id);
}
......@@ -2,22 +2,17 @@ package de.helmholtz.marketplace.cerebrum.repository;
import de.helmholtz.marketplace.cerebrum.entities.MarketUser;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.security.access.prepost.PreAuthorize;
import java.util.Optional;
@RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface MarketUserRepository extends PagingAndSortingRepository<MarketUser, Long> {
public interface MarketUserRepository extends PagingAndSortingRepository<MarketUser, Long>
{
MarketUser findBySub(@Param("sub") String sub);
@PreAuthorize("hasAnyAuthority('ADMIN')")
MarketUser save(MarketUser user);
Optional<MarketUser> findByUuid(String uuid);
@SuppressWarnings("UnusedReturnValue")
Long deleteByUuid(String uuid);
}
\ No newline at end of file
......@@ -11,5 +11,6 @@ public interface OrganizationRepository
{
Optional<Organization> findByUuid(String uuid);
@SuppressWarnings("UnusedReturnValue")
Long deleteByUuid(String id);
}
package de.helmholtz.marketplace.cerebrum.repository.listeners;
import de.helmholtz.marketplace.cerebrum.entities.MarketUser;
import org.springframework.data.rest.core.annotation.*;
import java.util.logging.Logger;
@RepositoryEventHandler
public class MarketUserEventHandler
{
Logger logger = Logger.getLogger("Class MarketUserEventHandler");
public MarketUserEventHandler() {
super();
}
@HandleAfterCreate
public void handleMarketUserBeforeCreate(MarketUser user) {
logger.info("A new MarketUser is created successfully....");
String name = user.getFirstName();
}
}
\ No newline at end of file
package de.helmholtz.marketplace.cerebrum.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fge.jsonpatch.JsonPatch;
import com.github.fge.jsonpatch.JsonPatchException;
import org.springframework.data.domain.Sort;
import java.util.ArrayList;
import java.util.List;
public final class CerebrumControllerUtilities
{
private CerebrumControllerUtilities()
{ }
public static <T> T applyPatch(
JsonPatch patch, T target, Class<T> clazz) throws JsonPatchException, JsonProcessingException
{
ObjectMapper objectMapper = new ObjectMapper();
JsonNode patched = patch.apply(objectMapper.convertValue(target, JsonNode.class));
return objectMapper.treeToValue(patched, clazz);
}
public static List<Sort.Order> getOrders(List<String> sorts)
{
List<Sort.Order> orders = new ArrayList<>();
for (String sort: sorts) {
if (sort.contains(".")) {
String[] order = sort.split("\\.");
orders.add(new Sort.Order(
order[1].equals("asc") ?
Sort.Direction.ASC :
Sort.Direction.DESC, order[0])
);
} else {
orders.add(new Sort.Order(Sort.Direction.ASC, sort));
}
}
return orders;
}
}
......@@ -53,7 +53,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest
@AutoConfigureMockMvc
@TestInstance(value = Lifecycle.PER_CLASS)
public class OrganizationControllerTest
class OrganizationControllerTest
{
private static final String API_URI_PREFIX = "/api/v0";
private static final String ORG_API_URI = API_URI_PREFIX + "/organizations";
......
......@@ -29,7 +29,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class CerebrumExceptionHandlerTest
class CerebrumExceptionHandlerTest
{
private static final String API_URI_PREFIX = "/api/v0";
private static final String ORG_API_URI = API_URI_PREFIX + "/organizations";
......@@ -38,8 +38,8 @@ public class CerebrumExceptionHandlerTest
@Autowired private ObjectMapper objectMapper;
@MockBean private OrganizationRepository mockRepository;
@Test
public void whenTry_thenOK() throws Exception
@Test void
whenTry_thenOK() throws Exception
{
final MvcResult response = mockMvc.perform(get(API_URI_PREFIX))
.andExpect(status().isOk())
......@@ -48,8 +48,8 @@ public class CerebrumExceptionHandlerTest
}
// handleMethodArgumentTypeMismatch
@Test
public void whenMethodArgumentMismatch_thenBadRequest() throws Exception
@Test void
whenMethodArgumentMismatch_thenBadRequest() throws Exception
{
final MvcResult response = mockMvc.perform(get(ORG_API_URI + "?page=ccc "))
.andExpect(status().isBadRequest())
......@@ -62,8 +62,8 @@ public class CerebrumExceptionHandlerTest
}
// handleHttpMessageNotReadable
@Test
public void whenHttpMessageNotReadable_thenBadRequest() throws Exception
@Test void
whenHttpMessageNotReadable_thenBadRequest() throws Exception
{
Map<String, String> patch = new HashMap<>();
patch.put("path", "/abbreviation");
......@@ -84,8 +84,8 @@ public class CerebrumExceptionHandlerTest
}
// handleInvalidUuid
@Test
public void whenInvalidUuid_thenBadRequest() throws Exception
@Test void
whenInvalidUuid_thenBadRequest() throws Exception
{
String badUuid = "abc";
final MvcResult response = mockMvc.perform(
......@@ -101,8 +101,8 @@ public class CerebrumExceptionHandlerTest
}
// handleEntityNotFound
@Test
public void whenEntityNotFound_thenNotFound() throws Exception
@Test void
whenEntityNotFound_thenNotFound() throws Exception
{
String nonExistingUuid = "org-5189a7bc-d630-11ea-87d0-0242ac130004";
Organization kit = new Organization();
......@@ -128,8 +128,8 @@ public class CerebrumExceptionHandlerTest
}
// handleMethodArgumentNotValid
@Test
public void whenValidInput_thenBadRequest() throws Exception
@Test void
whenValidInput_thenBadRequest() throws Exception
{
Map<String, Object> organisation = new HashMap<>();
organisation.put("organisationName", "Forschungszentrum Jülich");
......@@ -149,8 +149,8 @@ public class CerebrumExceptionHandlerTest
}
//handleHttpRequestMethodNotSupported
@Test
public void whenHttpRequestMethodNotSupported_thenMethodNotAllowed() throws Exception
@Test void
whenHttpRequestMethodNotSupported_thenMethodNotAllowed() throws Exception
{
final MvcResult response = mockMvc.perform(delete(ORG_API_URI)
.header("Authorization", "Bearer " + TOKEN))
......@@ -165,8 +165,8 @@ public class CerebrumExceptionHandlerTest
}
// handleNoHandlerFoundException
@Test
public void whenNoHandlerForHttpRequest_thenNotFound() throws Exception
@Test void
whenNoHandlerForHttpRequest_thenNotFound() throws Exception
{
final MvcResult response = mockMvc.perform(delete(API_URI_PREFIX + "/xx")
.header("Authorization", "Bearer " + TOKEN))
......@@ -181,8 +181,8 @@ public class CerebrumExceptionHandlerTest
}
// handleHttpMediaTypeNotSupported
@Test
public void whenSendInvalidHttpMediaType_thenUnsupportedMediaType() throws Exception
@Test void
whenSendInvalidHttpMediaType_thenUnsupportedMediaType() throws Exception
{
Map<String, Object> organisation = new HashMap<>();
organisation.put("organisationName", "Forschungszentrum Jülich");
......@@ -202,8 +202,8 @@ public class CerebrumExceptionHandlerTest
}
// handleHttpMediaTypeNotAcceptable
@Test
public void whenSendInvalidHttpMediaType_thenNotAcceptableMediaType() throws Exception
@Test void
whenSendInvalidHttpMediaType_thenNotAcceptableMediaType() throws Exception
{
final MvcResult response = mockMvc.perform(get(ORG_API_URI)
.accept("application/xml"))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment