Skip to content

Commit

Permalink
initial commit of exposing endpoint for opensearch
Browse files Browse the repository at this point in the history
  • Loading branch information
rajadilipkolli committed Sep 21, 2023
1 parent 7d3f0fc commit 4e867dd
Show file tree
Hide file tree
Showing 10 changed files with 689 additions and 6 deletions.
11 changes: 6 additions & 5 deletions boot-opensearch-sample/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.opensearch.client</groupId>
<artifactId>spring-data-opensearch-starter</artifactId>
<version>1.2.0</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
Expand Down Expand Up @@ -83,11 +89,6 @@
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.example.opensearch.entities;

import jakarta.validation.constraints.NotEmpty;
import java.util.Objects;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;

@Document(indexName = "restaurants")
public class Restaurant {

@Id private Long id;

@NotEmpty(message = "Name cannot be empty")
private String name;

public Restaurant() {}

public Restaurant(Long id, String name) {
this.id = id;
this.name = name;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Restaurant that = (Restaurant) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name);
}

@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.example.opensearch.model.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import org.springframework.data.domain.Page;

public record PagedResult<T>(
List<T> data,
long totalElements,
int pageNumber,
int totalPages,
@JsonProperty("isFirst") boolean isFirst,
@JsonProperty("isLast") boolean isLast,
@JsonProperty("hasNext") boolean hasNext,
@JsonProperty("hasPrevious") boolean hasPrevious) {
public PagedResult(Page<T> page) {
this(
page.getContent(),
page.getTotalElements(),
page.getNumber() + 1,
page.getTotalPages(),
page.isFirst(),
page.isLast(),
page.hasNext(),
page.hasPrevious());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.opensearch.repositories;

import com.example.opensearch.entities.Restaurant;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.repository.ListCrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface RestaurantRepository
extends ElasticsearchRepository<Restaurant, Long>, ListCrudRepository<Restaurant, Long> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.example.opensearch.services;

import com.example.opensearch.entities.Restaurant;
import com.example.opensearch.model.response.PagedResult;
import com.example.opensearch.repositories.RestaurantRepository;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class RestaurantService {

private final RestaurantRepository restaurantRepository;

@Autowired
public RestaurantService(RestaurantRepository restaurantRepository) {
this.restaurantRepository = restaurantRepository;
}

public PagedResult<Restaurant> findAllRestaurants(
int pageNo, int pageSize, String sortBy, String sortDir) {
Sort sort =
sortDir.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortBy).ascending()
: Sort.by(sortBy).descending();

// create Pageable instance
Pageable pageable = PageRequest.of(pageNo, pageSize, sort);
Page<Restaurant> restaurantsPage = restaurantRepository.findAll(pageable);

return new PagedResult<>(restaurantsPage);
}

public Optional<Restaurant> findRestaurantById(Long id) {
return restaurantRepository.findById(id);
}

public Restaurant saveRestaurant(Restaurant restaurant) {
return restaurantRepository.save(restaurant);
}

public void deleteRestaurantById(Long id) {
restaurantRepository.deleteById(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.example.opensearch.web.controllers;

import com.example.opensearch.entities.Restaurant;
import com.example.opensearch.model.response.PagedResult;
import com.example.opensearch.services.RestaurantService;
import com.example.opensearch.utils.AppConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/restaurants")
public class RestaurantController {

private final Logger log = LoggerFactory.getLogger(this.getClass());

private final RestaurantService restaurantService;

@Autowired
public RestaurantController(RestaurantService restaurantService) {
this.restaurantService = restaurantService;
}

@GetMapping
public PagedResult<Restaurant> getAllRestaurants(
@RequestParam(
value = "pageNo",
defaultValue = AppConstants.DEFAULT_PAGE_NUMBER,
required = false)
int pageNo,
@RequestParam(
value = "pageSize",
defaultValue = AppConstants.DEFAULT_PAGE_SIZE,
required = false)
int pageSize,
@RequestParam(
value = "sortBy",
defaultValue = AppConstants.DEFAULT_SORT_BY,
required = false)
String sortBy,
@RequestParam(
value = "sortDir",
defaultValue = AppConstants.DEFAULT_SORT_DIRECTION,
required = false)
String sortDir) {
return restaurantService.findAllRestaurants(pageNo, pageSize, sortBy, sortDir);
}

@GetMapping("/{id}")
public ResponseEntity<Restaurant> getRestaurantById(@PathVariable Long id) {
return restaurantService
.findRestaurantById(id)
.map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Restaurant createRestaurant(@RequestBody @Validated Restaurant restaurant) {
return restaurantService.saveRestaurant(restaurant);
}

@PutMapping("/{id}")
public ResponseEntity<Restaurant> updateRestaurant(
@PathVariable Long id, @RequestBody Restaurant restaurant) {
return restaurantService
.findRestaurantById(id)
.map(
restaurantObj -> {
restaurant.setId(id);
return ResponseEntity.ok(restaurantService.saveRestaurant(restaurant));
})
.orElseGet(() -> ResponseEntity.notFound().build());
}

@DeleteMapping("/{id}")
public ResponseEntity<Restaurant> deleteRestaurant(@PathVariable Long id) {
return restaurantService
.findRestaurantById(id)
.map(
restaurant -> {
restaurantService.deleteRestaurantById(id);
return ResponseEntity.ok(restaurant);
})
.orElseGet(() -> ResponseEntity.notFound().build());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
package com.example.opensearch.common;

import java.net.HttpURLConnection;
import java.time.Duration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;

@TestConfiguration(proxyBeanMethods = false)
public class ContainersConfig {}
public class ContainersConfig {

@Bean
@ServiceConnection("elasticsearch")
GenericContainer<?> createOpenSearchContainer() {
return new GenericContainer<>("opensearchproject/opensearch:1.1.0")
.withEnv("discovery.type", "single-node")
.withEnv("DISABLE_SECURITY_PLUGIN", "true")
.withEnv("OPENSEARCH_JAVA_OPTS", "-Xms512m -Xmx512m")
.withExposedPorts(9200, 9600)
.waitingFor(
new HttpWaitStrategy()
.forPort(9200)
.forStatusCodeMatching(
response ->
response == HttpURLConnection.HTTP_OK
|| response
== HttpURLConnection
.HTTP_UNAUTHORIZED)
.withStartupTimeout(Duration.ofMinutes(2)));
}
}
Loading

0 comments on commit 4e867dd

Please sign in to comment.