# Лабораторная работа 3

## 1. Задание

Разработка распределённого приложения с использованием Spring Boot.  
Нужно реализовать параллельный вариант алгоритма с применением сервис-ориентированного подхода, замерить время работы алгоритма и распределить функционал между двумя сервисами:  
- **Compute Service:** Находит минимальный элемент матрицы ниже главной диагонали.  
- **Gateway Service:** Принимает запросы от клиента и пересылает их на Compute Service.

**Вариант:** Определить минимальный элемент матрицы ниже главной диагонали.

---

## 2. Описание кода

Приложение состоит из двух частей, каждая из которых – отдельное Spring Boot приложение.

### 2.1. Compute Service

Этот сервис отвечает за вычисления. Он принимает матрицу, запускает алгоритм поиска минимального элемента ниже главной диагонали, замеряет время выполнения и возвращает результат.

#### MatrixComputeApplication.java

```java
package ru.kuznec;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MatrixComputeApplication {
    public static void main(String[] args) {
        SpringApplication.run(MatrixComputeApplication.class, args);
    }
}
```

#### MatrixComputeController.java

```java
package ru.kuznec;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
public class MatrixComputeController {

    @Autowired
    private MatrixMinService matrixMinService;

    @PostMapping("/computeMin")
    public ResponseEntity<Map<String, Object>> computeMin(@RequestBody int[][] matrix) {
        long startTime = System.nanoTime();
        int min = matrixMinService.findMinBelowMainDiagonal(matrix);
        long endTime = System.nanoTime();
        double duration = (double) (endTime - startTime) / 1_000_000;
        
        Map<String, Object> response = new HashMap<>();
        response.put("minValue", min);
        response.put("durationMs", duration);
        return ResponseEntity.ok(response);
    }
}
```

#### MatrixMinService.java

```java
package ru.kuznec;

import org.springframework.stereotype.Service;
import java.util.stream.IntStream;

@Service
public class MatrixMinService {

    public int findMinBelowMainDiagonal(int[][] matrix) {
        return IntStream.range(1, matrix.length)
                .parallel()
                .map(i -> {
                    int rowMin = Integer.MAX_VALUE;
                    for (int j = 0; j < i; j++) {
                        if (matrix[i][j] < rowMin) {
                            rowMin = matrix[i][j];
                        }
                    }
                    return rowMin;
                })
                .min()
                .orElse(Integer.MAX_VALUE);
    }
}
```

---

### 2.2. Gateway Service

Этот сервис принимает клиентские запросы на эндпоинте `/findMin` и пересылает их на Compute Service. В настройках Gateway указан URL Compute Service с его IP-адресом (в нашем случае, например, `http://192.168.10.101:8080/computeMin`).

#### MatrixGatewayApplication.java

```java
package ru.kuznec;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MatrixGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(MatrixGatewayApplication.class, args);
    }
}
```

#### MatrixGatewayController.java

```java
package ru.kuznec;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Map;

@RestController
public class MatrixGatewayController {

    @Autowired
    private RestTemplate restTemplate;

    // Адрес Compute Service (IP контейнера с Compute Service)
    private String computeServiceUrl = "http://192.168.10.101:8080/computeMin";

    @PostMapping("/findMin")
    public ResponseEntity<?> findMin(@RequestBody int[][] matrix) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<int[][]> request = new HttpEntity<>(matrix, headers);

        ResponseEntity<Map> response = restTemplate.exchange(
                computeServiceUrl,
                HttpMethod.POST,
                request,
                Map.class
        );
        return response;
    }
}
```

#### RestTemplateConfig.java

```java
package ru.kuznec;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
```

---

## 3. Запуск приложения

Сборка каждого приложения приводит к созданию jar-файлов. Запускаем их на разных контейнерах:

- **Compute Service:**  
  На контейнере с IP `192.168.10.101` запускаем:
  ```bash
  java -jar Lab-3.jar --server.port=8080
  ```
  Compute Service будет доступен по адресу:
  ```
  http://192.168.10.101:8080/computeMin
  ```

- **Gateway Service:**  
  На контейнере с IP `192.168.10.102` запускаем:
  ```bash
  java -jar Lab-3.1.jar --server.port=8081
  ```
  Gateway Service будет доступен по адресу:
  ```
  http://192.168.10.102:8081/findMin
  ```

Gateway Service перенаправляет запросы на Compute Service по указанному адресу.

---

## 4. Проверка работы

Для проверки работы можно использовать curl, отправив запрос на Gateway Service:

```bash
curl -X POST http://192.168.10.102:8081/findMin \
     -H "Content-Type: application/json" \
     -d '[[5, 3, 8], [2, 6, 4], [7, 1, 9]]'
```

В ответ вы получите JSON с полями `minValue` (минимальное значение) и `durationMs` (время выполнения алгоритма в миллисекундах).