Skip to content

Commit

Permalink
Events are being sinked.
Browse files Browse the repository at this point in the history
  • Loading branch information
cstroe committed Feb 4, 2019
1 parent 9af2868 commit 42487fa
Show file tree
Hide file tree
Showing 20 changed files with 242 additions and 183 deletions.
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ repositories {
}

group = "cloud.cosmin.checklister"
version = "0.0.9-SNAPSHOT"

val compileKotlin: KotlinCompile by tasks

Expand Down
7 changes: 1 addition & 6 deletions src/main/kotlin/cloud/cosmin/checklister/dto/Dtos.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@ data class ItemGetDto(var id: UUID?,
var rank: Int?)

data class ItemPostDto(
@JsonProperty var content: String?,
@JsonProperty var contentType: String?
)

data class ItemUpdateDto(
@JsonProperty var id: UUID,
@JsonProperty var list: UUID?,
@JsonProperty var content: String?,
@JsonProperty var contentType: String?
)
Expand Down
21 changes: 12 additions & 9 deletions src/main/kotlin/cloud/cosmin/checklister/rest/ItemController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ package cloud.cosmin.checklister.rest

import cloud.cosmin.checklister.dto.ItemGetDto
import cloud.cosmin.checklister.dto.ItemPostDto
import cloud.cosmin.checklister.dto.ItemUpdateDto
import cloud.cosmin.checklister.repo.ItemRepo
import cloud.cosmin.checklister.service.ConverterService
import cloud.cosmin.checklister.service.ItemService
import cloud.cosmin.checklister.service.RankOperation
import com.fasterxml.jackson.databind.ObjectMapper
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.*
import java.net.URI
import java.util.*

@Controller
Expand All @@ -38,16 +35,22 @@ constructor(private val itemService: ItemService) {
return ResponseEntity.ok(optionalItem.get())
}

@PostMapping("/api/v1/item")
@ApiOperation("Create an item")
fun createItem(@RequestBody dto: ItemPostDto): ResponseEntity<ItemGetDto> {
val createdItem = itemService.create(dto)
return ResponseEntity
.created(URI.create("/api/v1/item/" + createdItem.id))
.body(createdItem)
}


@PutMapping("/api/v1/item/{itemId}")
@ApiOperation("Update an item")
fun updateItem(@PathVariable itemId: UUID,
@RequestBody dto: ItemPostDto): ResponseEntity<ItemGetDto> {
val updated = itemService.update(itemId, dto)
return if(updated.isPresent) {
ResponseEntity.ok(updated.get())
} else {
ResponseEntity.notFound().build()
}
return ResponseEntity.ok(updated)
}

@PostMapping("/api/v1/item/{itemId}/rank/up")
Expand Down
29 changes: 0 additions & 29 deletions src/main/kotlin/cloud/cosmin/checklister/rest/ListController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -106,35 +106,6 @@ constructor(
return ResponseEntity.ok(dto)
}

@PostMapping("/api/v1/list/{listId}/item")
@ApiOperation("Add an item to the list")
fun createListItem(@PathVariable listId: UUID?,
@RequestBody itemDto: ItemPostDto): ResponseEntity<ItemGetDto> {
if (listId == null) {
return ResponseEntity.badRequest().build()
}

val optionalList = listRepo.findById(listId)
if (!optionalList.isPresent) {
return ResponseEntity.notFound().build()
}

val list = optionalList.get()

val newItem = ItemEntity()
newItem.content = itemDto.content
newItem.contentType = itemDto.contentType
newItem.rank = (list.items!!.size + 1) * 2
newItem.list = list

val savedItem = itemRepo.save(newItem)
val dto = converterService.itemDto(savedItem)

return ResponseEntity
.created(URI.create("/api/v1/list/" + listId.toString() + "/item/" + savedItem.id))
.body(dto)
}

// TODO: Add endpoint for direct item access (/api/v1/item/{itemId}) ?
@GetMapping("/api/v1/list/{listId}/item/{itemId}")
@ApiOperation("Retrieve a single item from a list")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package cloud.cosmin.checklister.service

import org.springframework.stereotype.Service
import java.io.File
import java.io.FileInputStream
import java.util.*

@Service
Expand All @@ -10,12 +12,27 @@ class BuildConfigService {
.getResourceAsStream("/checklister-build.properties")

return when(stream) {
null -> "null"
null -> readVersionFromLocalFile()
else -> {
val props = Properties()
props.load(stream)
props.getProperty("version")
}
}
}

/*
* When running directly from IDE.
*/
private fun readVersionFromLocalFile(): String {
val gradleProperties = File("gradle.properties")
if(gradleProperties.exists()) {
val fis = FileInputStream(gradleProperties)
val props = Properties()
props.load(fis)
return props.getProperty("version") ?: "null"
} else {
return "null"
}
}
}
6 changes: 0 additions & 6 deletions src/main/kotlin/cloud/cosmin/checklister/service/EventSink.kt

This file was deleted.

36 changes: 32 additions & 4 deletions src/main/kotlin/cloud/cosmin/checklister/service/ItemEvent.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
package cloud.cosmin.checklister.service

import cloud.cosmin.checklister.dto.ItemPostDto
import cloud.cosmin.checklister.dto.ItemGetDto
import cloud.cosmin.checklister.service.event.Event
import cloud.cosmin.checklister.service.event.ToStringEventSerializer
import java.util.*

enum class ListEventType {
CREATE, UPDATE, ADD
}

enum class ItemEventType {
UPDATE, RANK
CREATE, UPDATE, RANK
}

abstract class AbstractEvent : Event {
private val eventSerializer = ToStringEventSerializer()
override fun serialize(): ByteArray {
return eventSerializer.serialize(this)
}
}

data class ItemUpdateEvent(val type: ItemEventType, val id: UUID, val item: ItemPostDto)
data class ListCreateEvent(
val type: ItemEventType)

data class ItemCreateEvent(
val type: ItemEventType,
val id: UUID,
val item: ItemGetDto) : AbstractEvent()

data class ItemUpdateEvent(
val type: ItemEventType,
val id: UUID,
val item: ItemGetDto) : AbstractEvent()

data class ItemRankEvent(val type: ItemEventType, val id: UUID, val op: RankOperation, val newRank: Int)
data class ItemRankEvent(
val type: ItemEventType,
val id: UUID,
val op: RankOperation,
val item: ItemGetDto) : AbstractEvent()
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cloud.cosmin.checklister.service

import cloud.cosmin.checklister.dto.ItemPostDto
import cloud.cosmin.checklister.dto.ItemGetDto
import cloud.cosmin.checklister.service.event.EventSink
import org.springframework.stereotype.Service
import java.util.*

Expand All @@ -9,13 +10,18 @@ import java.util.*
*/
@Service
class ItemEventService(private val eventSink: EventSink) : ItemEvents {
override fun update(id: UUID, dto: ItemPostDto) {
override fun create(id: UUID, dto: ItemGetDto) {
val event = ItemCreateEvent(ItemEventType.CREATE, id, dto)
eventSink.accept(event)
}

override fun update(id: UUID, dto: ItemGetDto) {
val event = ItemUpdateEvent(ItemEventType.UPDATE, id, dto)
eventSink.accept(event)
}

override fun rank(id: UUID, op: RankOperation, newRank: Int) {
val event = ItemRankEvent(ItemEventType.RANK, id, op, newRank)
override fun rank(id: UUID, op: RankOperation, dto: ItemGetDto) {
val event = ItemRankEvent(ItemEventType.RANK, id, op, dto)
eventSink.accept(event)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package cloud.cosmin.checklister.service

import cloud.cosmin.checklister.dto.ItemPostDto
import cloud.cosmin.checklister.dto.ItemGetDto
import java.util.*

/**
* Actions on items that can be audited.
*/
interface ItemEvents {
fun update(id: UUID, dto: ItemPostDto): Unit
fun rank(id: UUID, op: RankOperation, newRank: Int): Unit
fun create(id: UUID, dto: ItemGetDto)
fun update(id: UUID, dto: ItemGetDto)
fun rank(id: UUID, op: RankOperation, dto: ItemGetDto)
}
48 changes: 39 additions & 9 deletions src/main/kotlin/cloud/cosmin/checklister/service/ItemService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,60 @@ import cloud.cosmin.checklister.dao.ItemEntity
import cloud.cosmin.checklister.dto.ItemGetDto
import cloud.cosmin.checklister.dto.ItemPostDto
import cloud.cosmin.checklister.repo.ItemRepo
import cloud.cosmin.checklister.repo.ListRepo
import org.springframework.stereotype.Service
import java.lang.RuntimeException
import java.util.*

@Service
class ItemService(val itemRepo: ItemRepo,
class ItemService(val listRepo: ListRepo,
val itemRepo: ItemRepo,
val converterService: ConverterService,
val itemEventService: ItemEventService) {
fun findById(id: UUID): Optional<ItemGetDto> {
return itemRepo.findById(id)
.map({ converterService.itemDto(it) })
.map { converterService.itemDto(it) }
}

fun update(id: UUID, dto: ItemPostDto): Optional<ItemGetDto> {
fun create(createdDto: ItemPostDto): ItemGetDto {
if (createdDto.list == null) {
throw RuntimeException("list field cannot be null")
}

val listId = createdDto.list!!
val optionalList = listRepo.findById(listId)
if (!optionalList.isPresent) {
throw RuntimeException("list cannot be found")
}

val list = optionalList.get()

val newItem = ItemEntity()
newItem.content = createdDto.content
newItem.contentType = createdDto.contentType
newItem.rank = (list.items!!.size + 1) * 2
newItem.list = list

val savedItem = itemRepo.save(newItem)
val dto = converterService.itemDto(savedItem)
itemEventService.create(savedItem.id!!, dto)
return dto
}

fun update(id: UUID, updatedDto: ItemPostDto): ItemGetDto {
val optionalItem = itemRepo.findById(id)
if (!optionalItem.isPresent) {
return Optional.empty()
throw RuntimeException("item not found with id: $id")
}

val item: ItemEntity = optionalItem.get()
item.content = dto.content
item.contentType = dto.contentType
item.content = updatedDto.content
item.contentType = updatedDto.contentType

val saved = itemRepo.save(item)
val dto = converterService.itemDto(saved)
itemEventService.update(id, dto)
return Optional.of(converterService.itemDto(saved))
return dto
}

fun rank(id: UUID, op: RankOperation): ItemGetDto {
Expand All @@ -39,7 +68,8 @@ class ItemService(val itemRepo: ItemRepo,
RankOperation.BOTTOM -> itemRepo.rankBottom(id)
}

itemEventService.rank(id, op, entity.rank)
return converterService.itemDto(entity)
val dto = converterService.itemDto(entity)
itemEventService.rank(id, op, dto)
return dto
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package cloud.cosmin.checklister.service.event

interface Event {
fun serialize(): ByteArray
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package cloud.cosmin.checklister.service.event

interface EventSerializer {
fun serialize(event: Event): ByteArray
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package cloud.cosmin.checklister.service.event

interface EventSink {
fun accept(event: Event)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package cloud.cosmin.checklister.service.event

class ToStringEventSerializer : EventSerializer {
override fun serialize(event: Event): ByteArray {
return event.toString().toByteArray(Charsets.UTF_8)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cloud.cosmin.checklister.service.event.eventsink

import cloud.cosmin.checklister.service.event.EventSink
import cloud.cosmin.checklister.service.event.Event
import org.apache.logging.log4j.LogManager
import org.springframework.stereotype.Service

@Service
class LoggerEventSink : EventSink {
private val log = LogManager.getLogger(javaClass)

override fun accept(event: Event) {
log.info("Event: {}", String(event.serialize()))
}
}

This file was deleted.

Loading

0 comments on commit 42487fa

Please sign in to comment.