hit-server-manager/backend/src/main/java/com/hitcommunications/servermanager/services/ServersService.java

255 lines
9.4 KiB
Java

package com.hitcommunications.servermanager.services;
import com.hitcommunications.servermanager.mappers.ServersMapper;
import com.hitcommunications.servermanager.model.Servers;
import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse;
import com.hitcommunications.servermanager.model.dtos.BulkServerImportResponse.FailedRow;
import com.hitcommunications.servermanager.model.dtos.NewServerDTO;
import com.hitcommunications.servermanager.model.dtos.ServerDTO;
import com.hitcommunications.servermanager.model.dtos.PagedResponse;
import com.hitcommunications.servermanager.model.enums.TypeCategory;
import com.hitcommunications.servermanager.repositories.ServersRepository;
import com.hitcommunications.servermanager.services.TypeOptionService;
import com.hitcommunications.servermanager.utils.TypeNormalizer;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@Service
@RequiredArgsConstructor
public class ServersService {
private static final int DEFAULT_PAGE_SIZE = 10;
private static final int MAX_PAGE_SIZE = 50;
private final ServersMapper mapper;
private final ServersRepository repo;
private final TypeOptionService typeOptionService;
public ServerDTO create(NewServerDTO createDTO) {
Servers entity = mapper.toEntity(createDTO);
applyNormalizedTypeData(entity, createDTO);
entity = repo.save(entity);
return mapper.toDTO(entity);
}
public ServerDTO getById(String id) {
return repo.findById(id)
.map(mapper::toDTO)
.orElseThrow(() -> new RuntimeException("Server not found with id: " + id));
}
public ServerDTO getByName(String name) {
return repo.findByName(name)
.map(mapper::toDTO)
.orElseThrow(() -> new RuntimeException("Server not found with name: " + name));
}
public List<ServerDTO> getByType(String type) {
String normalized = normalizeFilter(type, TypeCategory.SERVER_TYPE);
return repo.findByType(normalized)
.stream()
.map(mapper::toDTO)
.toList();
}
public Map<String, Integer> countAllByType() {
Map<String, Integer> response = new LinkedHashMap<>();
typeOptionService.list(TypeCategory.SERVER_TYPE).forEach(type -> {
response.put(type, repo.countAllByType(type));
});
// Garantir que valores existentes, mas não registrados, também apareçam
repo.findAll().stream()
.map(Servers::getType)
.filter(type -> type != null && !response.containsKey(type))
.distinct()
.forEach(type -> response.put(type, repo.countAllByType(type)));
return response;
}
public List<ServerDTO> getByApplication(String application) {
String normalized = normalizeFilter(application, TypeCategory.APPLICATION);
return repo.findByApplication(normalized)
.stream()
.map(mapper::toDTO)
.toList();
}
public BulkServerImportResponse bulkCreate(MultipartFile file) {
List<FailedRow> failures = new ArrayList<>();
int succeeded = 0;
int processed = 0;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8))) {
String line;
int lineNumber = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
if (line.isBlank()) {
continue;
}
String[] columns = parseColumns(line);
if (isHeaderRow(columns)) {
continue;
}
processed++;
try {
registerTypeOptionsFromRow(columns);
NewServerDTO dto = toNewServerDTO(columns);
create(dto);
succeeded++;
} catch (Exception ex) {
failures.add(new FailedRow(lineNumber, ex.getMessage(), line));
}
}
} catch (IOException e) {
throw new RuntimeException("Erro ao ler arquivo CSV.", e);
}
int failed = failures.size();
return new BulkServerImportResponse(processed, succeeded, failed, failures);
}
private String[] parseColumns(String line) {
String[] rawColumns = line.split(";");
String[] columns = new String[rawColumns.length];
for (int i = 0; i < rawColumns.length; i++) {
columns[i] = rawColumns[i].trim();
}
return columns;
}
private NewServerDTO toNewServerDTO(String[] columns) {
if (columns.length < 8) {
throw new IllegalArgumentException("Linha incompleta. Esperado 8 colunas.");
}
String name = columns[0];
String ip = columns[1];
Integer port = Integer.parseInt(columns[2]);
String user = columns[3];
String password = columns[4];
String type = columns[5];
String application = columns[6];
String dbType = columns[7];
return new NewServerDTO(name, ip, port, user, password, type, application, dbType);
}
private void registerTypeOptionsFromRow(String[] columns) {
if (columns.length < 8) {
return;
}
registerTypeOption(TypeCategory.SERVER_TYPE, columns[5]);
registerTypeOption(TypeCategory.APPLICATION, columns[6]);
registerTypeOption(TypeCategory.DATABASE, columns[7]);
}
private void registerTypeOption(TypeCategory category, String value) {
if (value == null || value.isBlank()) {
return;
}
typeOptionService.register(category, value);
}
private boolean isHeaderRow(String[] columns) {
if (columns.length < 8) {
return false;
}
return "name".equalsIgnoreCase(columns[0]) &&
"ip".equalsIgnoreCase(columns[1]) &&
"port".equalsIgnoreCase(columns[2]);
}
public List<ServerDTO> getAll() {
return repo.findAll()
.stream()
.map(mapper::toDTO)
.toList();
}
public PagedResponse<ServerDTO> search(String query, String type, String application, String dbType, Integer page, Integer size) {
String normalizedQuery = (query == null || query.isBlank()) ? null : query.trim();
String typeFilter = normalizeFilter(type, TypeCategory.SERVER_TYPE);
String applicationFilter = normalizeFilter(application, TypeCategory.APPLICATION);
String dbTypeFilter = normalizeFilter(dbType, TypeCategory.DATABASE);
int safePage = page != null && page >= 0 ? page : 0;
int requestedSize = (size != null && size > 0) ? size : DEFAULT_PAGE_SIZE;
int safeSize = Math.min(requestedSize, MAX_PAGE_SIZE);
Pageable pageable = PageRequest.of(safePage, safeSize);
Page<Servers> result = repo.search(normalizedQuery, typeFilter, applicationFilter, dbTypeFilter, pageable);
List<ServerDTO> content = result.getContent()
.stream()
.map(mapper::toDTO)
.toList();
return new PagedResponse<>(
content,
result.getTotalElements(),
result.getTotalPages(),
result.getNumber(),
result.getSize()
);
}
public ServerDTO update(String id, NewServerDTO updateDTO) {
Servers entity = repo.findById(id)
.orElseThrow(() -> new RuntimeException("Server not found with id: " + id));
mapper.partialUpdate(updateDTO, entity);
applyNormalizedTypeData(entity, updateDTO);
entity = repo.save(entity);
return mapper.toDTO(entity);
}
public void delete(String id) {
if (!repo.existsById(id)) {
throw new RuntimeException("Server not found with id: " + id);
}
repo.deleteById(id);
}
private void applyNormalizedTypeData(Servers entity, NewServerDTO dto) {
entity.setType(normalizeAndRegister(TypeCategory.SERVER_TYPE, dto.type()));
entity.setApplication(normalizeAndRegister(TypeCategory.APPLICATION, dto.application()));
entity.setDbType(normalizeAndRegister(TypeCategory.DATABASE, dto.dbType()));
}
private String normalizeFilter(String value, TypeCategory category) {
if (value == null || value.isBlank()) {
return null;
}
String normalized = TypeNormalizer.normalize(value);
if (normalized == null) {
return null;
}
typeOptionService.register(category, normalized);
return normalized;
}
private String normalizeAndRegister(TypeCategory category, String value) {
String normalized = TypeNormalizer.normalize(value);
if (normalized == null) {
throw new IllegalArgumentException("Valor inválido para " + category.name());
}
typeOptionService.register(category, normalized);
return normalized;
}
}