Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat/#452] 이벤트 라이브러리 구현 #463

Merged
merged 13 commits into from
Dec 22, 2024
Merged
11 changes: 11 additions & 0 deletions event/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
tasks.getByName("bootJar") {
enabled = false
}

tasks.getByName("jar") {
enabled = true
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-json")
}
23 changes: 23 additions & 0 deletions event/src/main/kotlin/event/Event.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package event

/**
* Event
*
* 이벤트
*
* @property eventId 이벤트 식별자
* @property eventType 이벤트 행위 타입
* @property eventTime 이벤트 발행 시간 (기본값: 현재 시간)
*/
abstract class Event(
protected val eventId: String = EventUtils.generateEventId(),
protected val eventType: String,
protected val eventTime: Long = System.currentTimeMillis(),
) {
/**
* Get data
*
* @return 이벤트 데이터
*/
abstract fun getData(): Map<String, Any>
}
14 changes: 14 additions & 0 deletions event/src/main/kotlin/event/EventDetails.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package event

/**
* Event details
*
* 이벤트 상세 정보
*
* @property outBox 이벤트 외부 발행 여부
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class EventDetails(
val outBox: Boolean = false,
)
18 changes: 18 additions & 0 deletions event/src/main/kotlin/event/EventHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package event

/**
* Event handler
*
* 이벤트 핸들러
*
* @param T Event 클래스를 상속 받은 클래스
* @see Event
*/
interface EventHandler<T : Event> {
/**
* Handle event
*
* @param event 이벤트
*/
fun handle(event: T)
}
15 changes: 15 additions & 0 deletions event/src/main/kotlin/event/EventRePlayer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package event

/**
* Event RePlayer
*
* 이벤트 재생기
*/
abstract class EventRePlayer {
/**
* Replay
*
* 정상 처리 되지 않은 이벤트를 재생합니다.
*/
abstract fun replay()
}
26 changes: 26 additions & 0 deletions event/src/main/kotlin/event/EventUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package event

import java.util.*

/**
* Is out box extension for Event Class
*
* 이벤트 외부 발행 여부를 확인합니다.
*
* @return 이벤트 외부 발행 여부
* @see Event
*/
fun Event.isOutBox(): Boolean = this::class.annotations.any { annotation -> annotation is EventDetails && annotation.outBox }

class EventUtils {
companion object {
/**
* Generate event id
*
* 이벤트 ID를 생성합니다.
*
* @return 이벤트 ID
*/
fun generateEventId(): String = UUID.randomUUID().toString()
}
}
83 changes: 83 additions & 0 deletions event/src/main/kotlin/event/TimeOutEvent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package event

import org.springframework.context.ApplicationEventPublisher

/**
* Time out event
*
* 시간이 설정된 이벤트
*
* @param expiredTime 만료 시간
* @param completed 완료 여부(기본값: false)
* @param eventPublisher 이벤트 발행자
*
* @see TimeExpiredEvent 시간 만료 이벤트
*/
abstract class TimeOutEvent(
eventId: String = EventUtils.generateEventId(),
eventType: String,
eventTime: Long = System.currentTimeMillis(),
protected val expiredTime: Long,
protected var completed: Boolean = false,
protected val eventPublisher: ApplicationEventPublisher,
) : Event(
eventId,
eventType,
eventTime,
),
Runnable {
/**
* Complete event
*
* 이벤트 완료 처리
*/
fun complete() {
completed = true
}

/**
* Is expired
*
* @param time 시간 (기본값: 현재 시간)
* @return 이벤트 만료 여부
*/
fun isExpired(time: Long = System.currentTimeMillis()): Boolean = !completed && time > expiredTime

/**
* Run
*
* 이벤트 만료시 실행
*/
override fun run() {
publishExpiredTimeEvent()
}

/**
* Publish expired time event
*
* 시간 만료 이벤트 발행
*/
private fun publishExpiredTimeEvent() {
eventPublisher.publishEvent(timeExpiredEvent())
}

/**
* Expired time event
*
* 시간 만료 이벤트
*/
abstract fun timeExpiredEvent(): TimeExpiredEvent
}

/**
* Expired time event
*/
abstract class TimeExpiredEvent(
eventId: String,
eventType: String,
eventTime: Long,
) : Event(
eventId,
eventType,
eventTime,
)
13 changes: 13 additions & 0 deletions event/src/main/kotlin/event/config/EventConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package event.config

import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration

@Configuration
@ComponentScan(basePackages = [EventConfig.BASE_PACKAGE])
class EventConfig {
companion object {
const val BASE_PACKAGE = "event"
const val BEAN_NAME_PREFIX = "event"
}
}
30 changes: 30 additions & 0 deletions event/src/main/kotlin/event/message/Message.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package event.message

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

/**
* Message
*
* 외부 시스템과의 통신을 위한 메시지
*
* @property payload 메시지 페이로드
*/
abstract class Message
@JsonCreator
constructor(
@JsonProperty("payload") var payload: MessagePayload?,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false

other as Message

if (payload != other.payload) return false

return true
}

override fun hashCode(): Int = payload?.hashCode() ?: 0
}
27 changes: 27 additions & 0 deletions event/src/main/kotlin/event/message/MessageMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package event.message

import event.Event
import java.util.Optional

/**
* Message mapper
*
* 이벤트를 메시지로 변환하기 위한 매퍼
*
* @param T Event 클래스를 상속 받은 클래스
* @param R Message 클래스를 상속 받은 클래스
*
* @see Event
* @see Message
*/
abstract class MessageMapper<T : Event, R : Message> {
/**
* Map
*
* 이벤트를 메시지로 변환
*
* @param event 이벤트
* @return Optional<Message> 메시지
*/
abstract fun map(event: T): Optional<R>
}
26 changes: 26 additions & 0 deletions event/src/main/kotlin/event/message/MessagePayload.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package event.message

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty

/**
* Message payload
*
* 메시지 페이로드
*
* @property eventId 이벤트 식별자
* @property eventType 이벤트 행위 타입
* @property eventTime 이벤트 발행 시간
* @property data 이벤트 데이터
*
* @see event.Event
*/

data class MessagePayload
@JsonCreator
constructor(
@JsonProperty("eventId") val eventId: String?,
@JsonProperty("eventType") val eventType: String?,
@JsonProperty("eventTime") val eventTime: Long?,
@JsonProperty("data") val data: Map<String, Any>?,
)
18 changes: 18 additions & 0 deletions event/src/main/kotlin/event/message/MessageRelay.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package event.message

/**
* Message relay
*
* 내부 이벤트를 외부에 메시지로 전달하기 위한 메시지 릴레이
*
* @param T Message 클래스를 상속 받은 클래스
* @see MessageSender 메시지를 전달하기 위한 메시지 발신자
*/
interface MessageRelay<T : Message> {
/**
* Publish
*
* @param message 외부로 전달할 메시지
*/
fun publish(message: T)
}
46 changes: 46 additions & 0 deletions event/src/main/kotlin/event/message/MessageReverseRelay.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package event.message

import event.Event

/**
* Message reverse relay
*
* 외부 시스템에서 전달 받은 메시지를 내부에 이벤트로 전달하기 위한 메시지 리버스 릴레이
*
* `Bar 메시지를 수신하여 Foo 이벤트로 변환하여 내부로 전달하는 예시`
*
* ```kotlin
* class FooBarLocalMessageReverseRelay(
* private val messageSender: MessageSender<BarMessage>,
* private val messageMapper: MessageMapper<FooEvent, BarMessage>,
* private val eventPublisher: ApplicationEventPublisher,
* ) : MessageReverseRelay<FooEvent> {
*
* override fun publish(event: FooEvent) {
* applicationEventPublisher.publishEvent(event)
* }
*
* @EventListener
* @LocalSubscribeMessage(topic ="bar")
* fun onApplicationEvent(message: BarMessage) {
* messageMapper.map(message).ifPresent { publish(it) }
* }
* }
* ```
* @param T Event 클래스를 상속 받은 클래스
*
* @see MessageSender 메시지를 전달하기 위한 메시지 발신자
* @see MessageMapper 메시지를 이벤트로 변환하기 위한 메시지 매퍼
* @see event.message.local.LocalSubscribeMessage 내부 메시지 수신을 위한 어노테이션
*
* @see org.springframework.context.event.EventListener 이벤트 리스너 (기본 설정 메서드 명: onApplicationEvent)
* @see org.springframework.context.ApplicationEventPublisher
*/
interface MessageReverseRelay<T : Event> {
/**
* Publish
*
* @param event 내부로 전달할 이벤트
*/
fun publish(event: T)
}
17 changes: 17 additions & 0 deletions event/src/main/kotlin/event/message/MessageSender.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package event.message

/**
* Message sender
*
* 외부 시스템으로 메시지를 전달하기 위한 메시지 발신자
*
* @param T Message 클래스를 상속 받은 클래스
*/
interface MessageSender<T : Message> {
/**
* Send
*
* @param message 전달할 메시지
*/
fun send(message: T)
}
Loading
Loading