Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
import com.netcracker.cloud.dbaas.entity.pg.composite.CompositeStructure;
import com.netcracker.cloud.dbaas.exceptions.NamespaceCompositeValidationException;
import com.netcracker.cloud.dbaas.service.composite.CompositeNamespaceService;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import jakarta.annotation.security.RolesAllowed;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.jetbrains.annotations.NotNull;

import java.util.List;
Expand Down Expand Up @@ -85,7 +84,10 @@ public Response getAllCompositeStructures() {
log.info("Received request to get all composite structures");
List<CompositeStructure> compositeStructures = compositeService.getAllCompositeStructures();
List<CompositeStructureDto> compositeStructureResponse = compositeStructures.stream()
.map(compositeStructure -> new CompositeStructureDto(compositeStructure.getBaseline(), compositeStructure.getNamespaces()))
.map(compositeStructure -> CompositeStructureDto.builder()
.id(compositeStructure.getBaseline())
.namespaces(compositeStructure.getNamespaces())
.build())
.toList();
return Response.ok(compositeStructureResponse).build();
}
Expand All @@ -108,7 +110,11 @@ public Response getCompositeById(@PathParam("compositeId") String compositeId) {
if (composite.isEmpty()) {
return getNotFoundTmfErrorResponse(compositeId);
}
return Response.ok(new CompositeStructureDto(composite.get().getBaseline(), composite.get().getNamespaces())).build();
return Response.ok(CompositeStructureDto.builder()
.id(composite.get().getBaseline())
.namespaces(composite.get().getNamespaces())
.build())
.build();
}

@NotNull
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.netcracker.cloud.dbaas.dao.jpa;

import com.netcracker.cloud.dbaas.entity.pg.composite.CompositeProperties;
import com.netcracker.cloud.dbaas.repositories.dbaas.CompositeNamespaceModifyIndexesDbaasRepository;
import com.netcracker.cloud.dbaas.repositories.pg.jpa.CompositeNamespaceModifyIndexesRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;

import java.util.Optional;

@AllArgsConstructor
@ApplicationScoped
public class CompositeNamespaceModifyIndexesDbaasRepositoryImpl implements CompositeNamespaceModifyIndexesDbaasRepository {

private CompositeNamespaceModifyIndexesRepository compositeNamespaceModifyIndexesRepository;

@Override
public Optional<CompositeProperties> findByBaselineName(String baselineName) {
return compositeNamespaceModifyIndexesRepository.findByBaseline(baselineName);
}

@Transactional
@Override
public void save(CompositeProperties compositeNamespacesModifyIndex) {
compositeNamespaceModifyIndexesRepository.persist(compositeNamespacesModifyIndex);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.netcracker.cloud.dbaas.dto.composite;

import jakarta.validation.constraints.PositiveOrZero;
import lombok.*;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import lombok.Data;
import lombok.NonNull;

import java.math.BigDecimal;
import java.util.Set;

@Data
@AllArgsConstructor
@Builder
public class CompositeStructureDto {

@Schema(description = "Composite identifier. Usually it's baseline or origin baseline in blue-green scheme", required = true)
Expand All @@ -16,4 +19,8 @@ public class CompositeStructureDto {
@Schema(description = "Namespaces that are included in composite structure (baseline and satellites)", required = true)
@NonNull
private Set<String> namespaces;

@Schema(description = "Index of composite structure (changes on each composite struct modification)", required = true)
@PositiveOrZero
private Long modifyIndex;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.netcracker.cloud.dbaas.entity.pg.composite;

import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.UUID;

@Data
@NoArgsConstructor
@Table(name = "composite_properties")
@Entity(name = "CompositeProperties")
public class CompositeProperties {
@Id
@Column(name = "composite_namespace_id")
public UUID id;

@OneToOne(fetch = FetchType.LAZY)
@MapsId
@JoinColumn(name = "composite_namespace_id")
private CompositeNamespace compositeNamespace;

@Column(name = "modify_index", nullable = false)
private long modifyIndex;

public CompositeProperties(CompositeNamespace compositeNamespace, long modifyIndex) {
this.compositeNamespace = compositeNamespace;
this.modifyIndex = modifyIndex;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.netcracker.cloud.dbaas.repositories.dbaas;

import com.netcracker.cloud.dbaas.entity.pg.composite.CompositeProperties;

import java.util.Optional;

public interface CompositeNamespaceModifyIndexesDbaasRepository {
Optional<CompositeProperties> findByBaselineName(String baselineName);

void save(CompositeProperties compositeNamespacesModifyIndex);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.netcracker.cloud.dbaas.repositories.pg.jpa;

import com.netcracker.cloud.dbaas.entity.pg.composite.CompositeProperties;
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped;

import java.util.Optional;
import java.util.UUID;

@ApplicationScoped
public class CompositeNamespaceModifyIndexesRepository implements PanacheRepositoryBase<CompositeProperties, UUID> {

public Optional<CompositeProperties> findByBaseline(String baseline) {
return find(
"compositeNamespace.baseline",
baseline
).firstResultOptional();
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package com.netcracker.cloud.dbaas.service.composite;

import com.netcracker.cloud.dbaas.dto.Source;
import com.netcracker.cloud.dbaas.dto.composite.CompositeStructureDto;
import com.netcracker.cloud.dbaas.entity.pg.composite.CompositeNamespace;
import com.netcracker.cloud.dbaas.entity.pg.composite.CompositeProperties;
import com.netcracker.cloud.dbaas.entity.pg.composite.CompositeStructure;
import com.netcracker.cloud.dbaas.exceptions.NamespaceCompositeValidationException;
import com.netcracker.cloud.dbaas.repositories.dbaas.CompositeNamespaceDbaasRepository;
import com.netcracker.cloud.dbaas.repositories.dbaas.CompositeNamespaceModifyIndexesDbaasRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;

import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;

Expand All @@ -19,21 +23,39 @@
@ApplicationScoped
public class CompositeNamespaceService {

private CompositeNamespaceDbaasRepository compositeNamespaceDbaasRepository;
private final CompositeNamespaceDbaasRepository compositeNamespaceDbaasRepository;
private final CompositeNamespaceModifyIndexesDbaasRepository compositeNamespaceModifyIndexesDbaasRepository;
private final EntityManager entityManager;

public CompositeNamespaceService(CompositeNamespaceDbaasRepository compositeNamespaceDbaasRepository) {
public CompositeNamespaceService(CompositeNamespaceDbaasRepository compositeNamespaceDbaasRepository,
CompositeNamespaceModifyIndexesDbaasRepository compositeNamespaceModifyIndexesDbaasRepository,
EntityManager entityManager) {
this.compositeNamespaceDbaasRepository = compositeNamespaceDbaasRepository;
this.compositeNamespaceModifyIndexesDbaasRepository = compositeNamespaceModifyIndexesDbaasRepository;
this.entityManager = entityManager;
}

@Transactional
public void saveOrUpdateCompositeStructure(CompositeStructureDto compositeRequest) {
if (compositeRequest.getModifyIndex() != null) {
txLock(compositeRequest.getId());
Optional<CompositeProperties> currentModifyIndex = compositeNamespaceModifyIndexesDbaasRepository.findByBaselineName(compositeRequest.getId());
if (currentModifyIndex.isPresent() && compositeRequest.getModifyIndex() < currentModifyIndex.get().getModifyIndex()) {
throw new NamespaceCompositeValidationException(Source.builder().pointer("/modifyIndex").build(), "new modify index '%s' should be greater than current index '%s'".formatted(compositeRequest.getModifyIndex(), currentModifyIndex.get().getModifyIndex()));
}
}

deleteCompositeStructure(compositeRequest.getId());
compositeNamespaceDbaasRepository.flush(); // need to flush because jpa first tries to save data without deleting it
compositeRequest.getNamespaces().add(compositeRequest.getId());
List<CompositeNamespace> compositeNamespaces = compositeRequest.getNamespaces().stream()
.map(ns -> buildCompositeNamespace(compositeRequest, ns))
.toList();
compositeNamespaceDbaasRepository.saveAll(compositeNamespaces);
if (compositeRequest.getModifyIndex() != null) {
compositeNamespaceDbaasRepository.findBaselineByNamespace(compositeRequest.getId())
.ifPresent(compositeNamespace -> compositeNamespaceModifyIndexesDbaasRepository.save(new CompositeProperties(compositeNamespace, compositeRequest.getModifyIndex())));
}
}

@NotNull
Expand Down Expand Up @@ -95,4 +117,12 @@ public Optional<String> getBaselineByNamespace(String namespace) {
return compositeNamespaceDbaasRepository.findBaselineByNamespace(namespace)
.map(CompositeNamespace::getBaseline);
}

private void txLock(String baseline) {
entityManager.createNativeQuery(
"SELECT pg_advisory_xact_lock(hashtext(:baseline))"
)
.setParameter("baseline", baseline)
.getSingleResult();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
create table if not exists composite_properties
(
composite_namespace_id uuid primary key
references composite_namespace(id)
on delete cascade,
modify_index numeric(20) not null check (modify_index >= 0)
);
Loading
Loading