Skip to content

Commit

Permalink
Feature/1693 api v3 disabled fails validation (#2066)
Browse files Browse the repository at this point in the history
* #1693 As `disabled` flag cases to fail validation:
 - custom isDisabledCheck is not needed anymore (V3 services use `validate` for this)
 - `EntityDisabledException` removed, replaced by a `Validation` with `disabled` key.
 - validation fixed for Schemas (did not include super-check)
 - V3 integTests updated to cover the `disabled` = validation fail

* #1693 disable fail due to nonEmpty used in now carries a wrapper with an error message (`UsedIn` wrapped in `EntityInUseException`)

* #1693 `Future {throw x}` replaced with `Future.failed(x)` in rest_api, cleanup
  • Loading branch information
dk1844 authored May 31, 2022
1 parent 0c9bf73 commit 9cf521e
Show file tree
Hide file tree
Showing 23 changed files with 502 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,6 @@ class RestExceptionHandler {
ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).build[Any]() // Could change for LOCKED but I like this more
}

@ExceptionHandler(value = Array(classOf[EntityDisabledException]))
def handleEntityDisabled(exception: EntityDisabledException): ResponseEntity[EntityDisabledException] = {
ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception)
}

@ExceptionHandler(value = Array(classOf[SchemaParsingException]))
def handleBadRequestException(exception: SchemaParsingException): ResponseEntity[Any] = {
val response = RestResponse(exception.message, Option(SchemaParsingError.fromException(exception)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ abstract class VersionedModelController[C <: VersionedModel with Product with Au
@ResponseStatus(HttpStatus.CREATED)
def importSingleEntity(@AuthenticationPrincipal principal: UserDetails,
@RequestBody importObject: ExportableObject[C]): CompletableFuture[C] = {
versionedModelService.importSingleItemV2(importObject.item, principal.getUsername, importObject.metadata).map {
case Some(entity) => entity
versionedModelService.importSingleItem(importObject.item, principal.getUsername, importObject.metadata).map {
case Some((entity, validation)) => entity // validation is disregarded for V2, import-v2 has its own
case None => throw notFound()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

package za.co.absa.enceladus.rest_api.controllers.v3

import com.mongodb.client.result.UpdateResult
import org.springframework.http.{HttpStatus, ResponseEntity}
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.core.userdetails.UserDetails
Expand All @@ -26,9 +25,9 @@ import za.co.absa.enceladus.model.versionedModel._
import za.co.absa.enceladus.model.{ExportableObject, UsedIn, Validation}
import za.co.absa.enceladus.rest_api.controllers.BaseController
import za.co.absa.enceladus.rest_api.controllers.v3.VersionedModelControllerV3.LatestVersionKey
import za.co.absa.enceladus.rest_api.exceptions.{EntityDisabledException, NotFoundException, ValidationException}
import za.co.absa.enceladus.rest_api.exceptions.NotFoundException
import za.co.absa.enceladus.rest_api.models.rest.DisabledPayload
import za.co.absa.enceladus.rest_api.services.VersionedModelService
import za.co.absa.enceladus.rest_api.services.v3.VersionedModelServiceV3

import java.net.URI
import java.util.Optional
Expand All @@ -42,7 +41,7 @@ object VersionedModelControllerV3 {
}

abstract class VersionedModelControllerV3[C <: VersionedModel with Product
with Auditable[C]](versionedModelService: VersionedModelService[C]) extends BaseController {
with Auditable[C]](versionedModelService: VersionedModelServiceV3[C]) extends BaseController {

import za.co.absa.enceladus.rest_api.utils.implicits._

Expand Down Expand Up @@ -110,7 +109,7 @@ abstract class VersionedModelControllerV3[C <: VersionedModel with Product
if (name != importObject.item.name) {
Future.failed(new IllegalArgumentException(s"URL and payload entity name mismatch: '$name' != '${importObject.item.name}'"))
} else {
versionedModelService.importSingleItemV3(importObject.item, principal.getUsername, importObject.metadata).map {
versionedModelService.importSingleItem(importObject.item, principal.getUsername, importObject.metadata).map {
case Some((entity, validation)) =>
// stripping two last segments, instead of /api-v3/dastasets/dsName/import + /dsName/dsVersion we want /api-v3/dastasets + /dsName/dsVersion
createdWithNameVersionLocationBuilder(entity.name, entity.version, request, stripLastSegments = 2).body(validation)
Expand All @@ -131,13 +130,10 @@ abstract class VersionedModelControllerV3[C <: VersionedModel with Product
def create(@AuthenticationPrincipal principal: UserDetails,
@RequestBody item: C,
request: HttpServletRequest): CompletableFuture[ResponseEntity[Validation]] = {
versionedModelService.isDisabled(item.name).flatMap { isDisabled =>
if (isDisabled) {
Future.failed(EntityDisabledException(s"Entity ${item.name} is disabled. Enable it first (PUT) to push new versions (PUT)."))
} else {

// enabled check is part of the validation
versionedModelService.create(item, principal.getUsername)
}
}.map {
.map {
case Some((entity, validation)) => createdWithNameVersionLocationBuilder(entity.name, entity.version, request).body(validation)
case None => throw notFound()
}
Expand All @@ -156,16 +152,11 @@ abstract class VersionedModelControllerV3[C <: VersionedModel with Product
} else if (version != item.version) {
Future.failed(new IllegalArgumentException(s"URL and payload version mismatch: ${version} != ${item.version}"))
} else {
versionedModelService.isDisabled(item.name).flatMap { isDisabled =>
if (isDisabled) {
throw EntityDisabledException(s"Entity ${item.name} is disabled. Enable it first to create new versions.")
} else {
versionedModelService.update(user.getUsername, item).map {
case Some((updatedEntity, validation)) =>
createdWithNameVersionLocationBuilder(updatedEntity.name, updatedEntity.version, request, stripLastSegments = 2).body(validation)
case None => throw notFound()
}
}
// disable check is already part of V3 validation
versionedModelService.update(user.getUsername, item).map {
case Some((updatedEntity, validation)) =>
createdWithNameVersionLocationBuilder(updatedEntity.name, updatedEntity.version, request, stripLastSegments = 2).body(validation)
case None => throw notFound()
}
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ import scala.concurrent.Future
import za.co.absa.enceladus.rest_api.exceptions.NotFoundException

@Service
class AttachmentService @Autowired()(attachmentMongoRepository: AttachmentMongoRepository,
class AttachmentService @Autowired()(val mongoRepository: AttachmentMongoRepository,
schemaMongoRepository: SchemaMongoRepository,
datasetMongoRepository: DatasetMongoRepository,
mappingTableMongoRepository: MappingTableMongoRepository)
extends ModelService(attachmentMongoRepository) {
extends ModelService[MenasAttachment] {

protected val attachmentMongoRepository: AttachmentMongoRepository = mongoRepository // alias

import scala.concurrent.ExecutionContext.Implicits.global

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ import scala.util.{Failure, Success}


@Service
class DatasetService @Autowired()(datasetMongoRepository: DatasetMongoRepository,
class DatasetService @Autowired()(val mongoRepository: DatasetMongoRepository,
oozieRepository: OozieRepository,
propertyDefinitionService: PropertyDefinitionService)
extends VersionedModelService(datasetMongoRepository) {
extends VersionedModelService[Dataset] {

protected val datasetMongoRepository: DatasetMongoRepository = mongoRepository // alias

import scala.concurrent.ExecutionContext.Implicits.global

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import za.co.absa.enceladus.rest_api.repositories.{DatasetMongoRepository, Mappi
import scala.concurrent.Future

@Service
class MappingTableService @Autowired() (mappingTableMongoRepository: MappingTableMongoRepository,
datasetMongoRepository: DatasetMongoRepository) extends VersionedModelService(mappingTableMongoRepository) {
class MappingTableService @Autowired() (val mongoRepository: MappingTableMongoRepository,
datasetMongoRepository: DatasetMongoRepository) extends VersionedModelService[MappingTable] {

protected val mappingTableMongoRepository: MappingTableMongoRepository = mongoRepository // alias

import scala.concurrent.ExecutionContext.Implicits.global

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import za.co.absa.enceladus.rest_api.repositories.MongoRepository

import scala.concurrent.Future

abstract class ModelService[C](mongoRepository: MongoRepository[C]) {
trait ModelService[C] {

def mongoRepository: MongoRepository[C]

import scala.concurrent.ExecutionContext.Implicits.global

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@ package za.co.absa.enceladus.rest_api.services

import org.springframework.beans.factory.annotation.{Autowired, Value}
import org.springframework.stereotype.Service
import za.co.absa.enceladus.model.Run
import za.co.absa.enceladus.rest_api.repositories.MonitoringMongoRepository

import scala.concurrent.Future

@Service
class MonitoringService @Autowired()(monitoringMongoRepository: MonitoringMongoRepository)
extends ModelService(monitoringMongoRepository) {
class MonitoringService @Autowired()(val mongoRepository: MonitoringMongoRepository)
extends ModelService[Run] {

import scala.concurrent.ExecutionContext.Implicits.global

def getMonitoringDataPoints(datasetName: String, startDate: String, endDate: String): Future[String] = {
monitoringMongoRepository.getMonitoringDataPoints(datasetName, startDate, endDate).map(_.mkString("[", ",", "]"))
mongoRepository.getMonitoringDataPoints(datasetName, startDate, endDate).map(_.mkString("[", ",", "]"))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import za.co.absa.enceladus.model.properties.PropertyDefinition
import scala.concurrent.Future

@Service("propertyDefinitionService") // by-name qualifier: V2 implementations use the base implementation, not v3
class PropertyDefinitionService @Autowired()(propertyDefMongoRepository: PropertyDefinitionMongoRepository)
extends VersionedModelService(propertyDefMongoRepository) {
class PropertyDefinitionService @Autowired()(val mongoRepository: PropertyDefinitionMongoRepository)
extends VersionedModelService[PropertyDefinition] {

protected val propertyDefMongoRepository: PropertyDefinitionMongoRepository = mongoRepository // alias
import scala.concurrent.ExecutionContext.Implicits.global

override def getUsedIn(name: String, version: Option[Int]): Future[UsedIn] = {
Expand All @@ -44,7 +45,7 @@ class PropertyDefinitionService @Autowired()(propertyDefMongoRepository: Propert
}

def getDistinctCount(): Future[Int] = {
propertyDefMongoRepository.distinctCount()
mongoRepository.distinctCount()
}

override def create(newPropertyDef: PropertyDefinition, username: String): Future[Option[(PropertyDefinition, Validation)]] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ import scala.concurrent.Future
import scala.util.{Failure, Success, Try}

@Service
class RunService @Autowired()(runMongoRepository: RunMongoRepository)
extends ModelService(runMongoRepository) {
class RunService @Autowired()(val mongoRepository: RunMongoRepository)
extends ModelService[Run] {

protected val runMongoRepository: RunMongoRepository = mongoRepository // alias

def getRunSummariesPerDatasetName(): Future[Seq[RunDatasetNameGroupedSummary]] = {
runMongoRepository.getRunSummariesPerDatasetName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ import za.co.absa.enceladus.rest_api.utils.converters.SparkMenasSchemaConvertor
import scala.concurrent.Future

@Service
class SchemaService @Autowired() (schemaMongoRepository: SchemaMongoRepository,
class SchemaService @Autowired() (val mongoRepository: SchemaMongoRepository,
mappingTableMongoRepository: MappingTableMongoRepository,
datasetMongoRepository: DatasetMongoRepository,
sparkMenasConvertor: SparkMenasSchemaConvertor) extends VersionedModelService(schemaMongoRepository) {
sparkMenasConvertor: SparkMenasSchemaConvertor) extends VersionedModelService[Schema] {

protected val schemaMongoRepository: SchemaMongoRepository = mongoRepository // alias

import scala.concurrent.ExecutionContext.Implicits.global

Expand Down
Loading

0 comments on commit 9cf521e

Please sign in to comment.