Updated package prefix to use personal website

This commit is contained in:
2024-02-18 10:06:02 -07:00
parent 44d5325e39
commit ed26c2ba57
41 changed files with 107 additions and 114 deletions
+7 -11
View File
@@ -1,6 +1,6 @@
# Dynanmic, Reactive Alerting API (Proof-of-Concept)
# Simple Alerting API
This project is a proof-of-concept API for a dynamic, reactive alerting system.
This project is a simple API for a dynamic, reactive alerting system (minus the notification component).
It consists of four different modules that comprise the overall functionality of the project.
* amqp
@@ -8,18 +8,16 @@ It consists of four different modules that comprise the overall functionality of
* batch
* persistence
*Note that the notification component is not part of this proof-of-concept*
## Architecture
![alerting architecture](./alerting-architecture.png)
## Getting Started
1. Clone the project. `git clone git@github.com:Dark-Alex-17/alerting-poc.git`
2. Open the `alerting-poc` folder with IntelliJ. Use auto-import for a Gradle
1. Clone the project. `git clone git@github.com:Dark-Alex-17/alerting-api.git`
2. Open the `alerting-api` folder with IntelliJ. Use auto-import for a Gradle
project.
## Running the POC
## Running the API
### Start the persistence tier
The persistence tier will start up the in-memory H2 database. Once started,
Flyway will populate the database with the alerting schema and test data, and also
@@ -30,8 +28,6 @@ can use the database.
The H2 browser console is available at http://localhost:8081/h2-console
#### Start the Persistence Layer
`./gradlew persistence:bootRun`
### Start the batch worker
@@ -47,9 +43,9 @@ The API is how users provision alerts and recipients, and all data is persisted
Additionally, all operations send a message to RabbitMQ to provision and schedule Quartz jobs in the
batch worker.
The API is available at http://localhost:8080/poc/alerting/v1/
The API is available at http://localhost:8080/api/alerting/v1/
API documentation is available [here](https://dark-alex-17.github.io/alerting-poc/)
API documentation is available [here](https://dark-alex-17.github.io/alerting-api/)
`./gradlew api:bootRun`
@@ -1,4 +1,4 @@
package com.poc.alerting.amqp;
package com.alexjclarke.alerting.amqp;
import java.io.Serializable;
@@ -1,4 +1,4 @@
package com.poc.alerting.amqp;
package com.alexjclarke.alerting.amqp;
import java.io.Serializable;
@@ -1,4 +1,4 @@
package com.poc.alerting.amqp;
package com.alexjclarke.alerting.amqp;
public enum ExceptionType {
INVALID_REQUEST_EXCEPTION(400),
@@ -1,4 +1,4 @@
package com.poc.alerting.amqp;
package com.alexjclarke.alerting.amqp;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
@@ -1,4 +1,4 @@
package com.poc.alerting.amqp;
package com.alexjclarke.alerting.amqp;
import java.io.Serializable;
@@ -1,7 +1,6 @@
package com.poc.alerting.amqp;
package com.alexjclarke.alerting.amqp;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@@ -1,4 +1,4 @@
package com.poc.alerting.amqp
package com.alexjclarke.alerting.amqp
sealed class AlertingAmqpMessage(
val alertId: String,
@@ -9,7 +9,7 @@ sealed class AlertingAmqpMessage(
}
override fun getExchange(): String {
return "poc_alerting"
return "alerting_api"
}
class Add(val frequency: String, alertId: String, accountId: String): AlertingAmqpMessage(alertId, accountId)
@@ -1,4 +1,4 @@
package com.poc.alerting.amqp
package com.alexjclarke.alerting.amqp
import org.apache.commons.lang3.time.DateUtils.MILLIS_PER_MINUTE
import org.springframework.amqp.core.Binding
@@ -16,10 +16,10 @@ import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
@Configuration
@ComponentScan(basePackages = ["com.poc.alerting.amqp"])
@ComponentScan(basePackages = ["com.alexjclarke.alerting.amqp"])
open class AmqpConfiguration {
companion object {
const val AMQP_NAME = "poc_alerting"
const val AMQP_NAME = "alerting_api"
const val NEW_ACCOUNT = "new_account"
const val FANOUT_NAME = "${AMQP_NAME}_fanout"
}
@@ -27,8 +27,8 @@ open class AmqpConfiguration {
@Bean
open fun connectionFactory(): ConnectionFactory {
return CachingConnectionFactory().apply {
virtualHost = "poc"
username = "poc_user"
virtualHost = "api"
username = "api_user"
setPassword("s!mpleP@ssw0rd")
setAddresses("localhost")
}
@@ -50,7 +50,7 @@ open class AmqpConfiguration {
}
@Bean
open fun pocAlertingExchange(): FanoutExchange {
open fun alertingExchange(): FanoutExchange {
return FanoutExchange(FANOUT_NAME)
}
@@ -63,8 +63,8 @@ open class AmqpConfiguration {
}
@Bean
open fun exchangeBinding(directExchange: Exchange, pocAlertingExchange: FanoutExchange): Binding {
return BindingBuilder.bind(directExchange).to(pocAlertingExchange)
open fun exchangeBinding(directExchange: Exchange, alertingExchange: FanoutExchange): Binding {
return BindingBuilder.bind(directExchange).to(alertingExchange)
}
@Bean
+1 -1
View File
@@ -23,5 +23,5 @@ dependencies {
tasks.getByName<BootJar>("bootJar") {
enabled = true
mainClass.set("com.poc.alerting.api.AlertingApi")
mainClass.set("com.alexjclarke.alerting.api.AlertingApi")
}
@@ -1,4 +1,4 @@
package com.poc.alerting.api;
package com.alexjclarke.alerting.api;
import java.beans.FeatureDescriptor;
import java.util.List;
@@ -1,9 +1,9 @@
package com.poc.alerting.api
package com.alexjclarke.alerting.api
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication(scanBasePackages = ["com.poc.alerting"])
@SpringBootApplication(scanBasePackages = ["com.alexjclarke.alerting"])
open class AlertingApi
fun main(args: Array<String>) {
@@ -1,15 +1,15 @@
package com.poc.alerting.api.controller
package com.alexjclarke.alerting.api.controller
import com.poc.alerting.amqp.AlertingAmqpMessage.Add
import com.poc.alerting.amqp.AlertingAmqpMessage.Delete
import com.poc.alerting.amqp.AlertingAmqpMessage.Pause
import com.poc.alerting.amqp.AlertingAmqpMessage.Resume
import com.poc.alerting.amqp.AlertingAmqpMessage.Update
import com.poc.alerting.amqp.RabbitSender
import com.poc.alerting.api.PropertyCopier
import com.poc.alerting.persistence.dto.Alert
import com.poc.alerting.persistence.repositories.AccountRepository
import com.poc.alerting.persistence.repositories.AlertRepository
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Add
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Delete
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Pause
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Resume
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Update
import com.alexjclarke.alerting.amqp.RabbitSender
import com.alexjclarke.alerting.api.PropertyCopier
import com.alexjclarke.alerting.persistence.dto.Alert
import com.alexjclarke.alerting.persistence.repositories.AccountRepository
import com.alexjclarke.alerting.persistence.repositories.AlertRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
@@ -1,8 +1,8 @@
package com.poc.alerting.api.controller
package com.alexjclarke.alerting.api.controller
import com.poc.alerting.api.PropertyCopier
import com.poc.alerting.persistence.dto.Recipient
import com.poc.alerting.persistence.repositories.RecipientRepository
import com.alexjclarke.alerting.api.PropertyCopier
import com.alexjclarke.alerting.persistence.dto.Recipient
import com.alexjclarke.alerting.persistence.repositories.RecipientRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
+1 -1
View File
@@ -1,6 +1,6 @@
server:
servlet:
contextPath: "/poc/alerting/v1"
contextPath: "/api/alerting/v1"
port: 8080
spring:
jackson:
+2 -2
View File
@@ -21,9 +21,9 @@ dependencies {
tasks.getByName<BootJar>("bootJar") {
enabled = true
mainClass.set("com.poc.alerting.batch.BatchWorkerKt")
mainClass.set("com.alexjclarke.alerting.batch.BatchWorkerKt")
}
springBoot {
mainClass.set("com.poc.alerting.batch.BatchWorkerKt")
mainClass.set("com.alexjclarke.alerting.batch.BatchWorkerKt")
}
@@ -1,4 +1,4 @@
package com.poc.alerting.batch;
package com.alexjclarke.alerting.batch;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -1,4 +1,4 @@
package com.poc.alerting.batch;
package com.alexjclarke.alerting.batch;
import java.util.Base64;
import java.util.stream.StreamSupport;
@@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
@@ -37,7 +36,7 @@ public class ApplicationStartup implements ApplicationListener<ApplicationReadyE
LOG.info("Creating consumers for existing queues");
try {
final String rabbitMqUrl = String.format("http://%s:15672/api/exchanges/poc/alerting/bindings/source", "localhost");
final String rabbitMqUrl = String.format("http://%s:15672/api/exchanges/alexjclarke/alerting/bindings/source", "localhost");
//auth is kind of a kluge here. Apparently the HttpClient Fluent API doesn't support
//it except by explicitly setting the auth header.
@@ -59,7 +58,7 @@ public class ApplicationStartup implements ApplicationListener<ApplicationReadyE
}
private String getAuthToken() {
final String basicPlaintext = "poc" + ":" + "s!mpleP@ssw0rd";
final String basicPlaintext = "api_user" + ":" + "s!mpleP@ssw0rd";
final Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(basicPlaintext.getBytes());
@@ -1,4 +1,4 @@
package com.poc.alerting.batch;
package com.alexjclarke.alerting.batch;
import org.apache.commons.logging.Log;
import org.springframework.amqp.support.ConditionalExceptionLogger;
@@ -1,4 +1,4 @@
package com.poc.alerting.batch;
package com.alexjclarke.alerting.batch;
import java.io.IOException;
import java.util.Properties;
@@ -13,15 +13,14 @@ import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import com.poc.alerting.amqp.AmqpMessage;
import com.poc.alerting.amqp.AmqpResponse;
import com.poc.alerting.amqp.ExceptionType;
import com.alexjclarke.alerting.amqp.AmqpMessage;
import com.alexjclarke.alerting.amqp.AmqpResponse;
import com.alexjclarke.alerting.amqp.ExceptionType;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import static com.poc.alerting.amqp.AmqpConfiguration.AMQP_NAME;
import static com.poc.alerting.batch.WorkerConfiguration.NEW_CONSUMER;
import static com.alexjclarke.alerting.amqp.AmqpConfiguration.AMQP_NAME;
@Slf4j
@Component
@@ -60,6 +59,6 @@ public class QueueCreator {
}
private void sendCreateConsumerMessage(final String queueName) {
rabbitTemplate.convertAndSend(NEW_CONSUMER, "", queueName);
rabbitTemplate.convertAndSend(WorkerConfiguration.NEW_CONSUMER, "", queueName);
}
}
@@ -1,17 +1,17 @@
package com.poc.alerting.batch
package com.alexjclarke.alerting.batch
import com.poc.alerting.amqp.AlertingAmqpMessage
import com.poc.alerting.amqp.AlertingAmqpMessage.Add
import com.poc.alerting.amqp.AlertingAmqpMessage.Delete
import com.poc.alerting.amqp.AlertingAmqpMessage.Pause
import com.poc.alerting.amqp.AlertingAmqpMessage.Resume
import com.poc.alerting.amqp.AlertingAmqpMessage.Update
import com.poc.alerting.batch.jobs.AlertQueryJob
import com.poc.alerting.batch.jobs.AlertQueryJob.Companion.ACCOUNT_ID
import com.poc.alerting.batch.jobs.AlertQueryJob.Companion.ALERT_ID
import com.poc.alerting.batch.jobs.AlertQueryJob.Companion.CRON
import com.poc.alerting.persistence.dto.Alert
import com.poc.alerting.persistence.repositories.AlertRepository
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Add
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Delete
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Pause
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Resume
import com.alexjclarke.alerting.amqp.AlertingAmqpMessage.Update
import com.alexjclarke.alerting.batch.jobs.AlertQueryJob
import com.alexjclarke.alerting.batch.jobs.AlertQueryJob.Companion.ACCOUNT_ID
import com.alexjclarke.alerting.batch.jobs.AlertQueryJob.Companion.ALERT_ID
import com.alexjclarke.alerting.batch.jobs.AlertQueryJob.Companion.CRON
import com.alexjclarke.alerting.persistence.dto.Alert
import com.alexjclarke.alerting.persistence.repositories.AlertRepository
import org.quartz.CronScheduleBuilder
import org.quartz.JobBuilder
import org.quartz.JobDataMap
@@ -49,7 +49,7 @@ open class AccountWorker @Autowired constructor(
start()
}
return alertRepository.findByExtIdAndAccount_Id(alertId, accountId)
return alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId)
}
private fun updateJob(alertId: String, accountId: String, cron: String): Alert {
@@ -58,7 +58,7 @@ open class AccountWorker @Autowired constructor(
}
private fun deleteJob(alertId: String, accountId: String): Alert {
val alert = alertRepository.findByExtIdAndAccount_Id(alertId, accountId)
val alert = alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId)
scheduler.deleteJob(JobKey.jobKey(alertId, accountId))
alertRepository.delete(alert)
return alert
@@ -66,12 +66,12 @@ open class AccountWorker @Autowired constructor(
private fun pauseJob(alertId: String, accountId: String): Alert {
scheduler.pauseJob(JobKey.jobKey(alertId, accountId))
return alertRepository.findByExtIdAndAccount_Id(alertId, accountId)
return alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId)
}
private fun resumeJob(alertId: String, accountId: String): Alert {
scheduler.resumeJob(JobKey.jobKey(alertId, accountId))
return alertRepository.findByExtIdAndAccount_Id(alertId, accountId)
return alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId)
}
private fun buildJob(alertId: String, accountId: String, cron: String): JobDetail {
@@ -1,4 +1,4 @@
package com.poc.alerting.batch
package com.alexjclarke.alerting.batch
import org.quartz.Job
import org.quartz.SchedulerContext
@@ -1,11 +1,11 @@
package com.poc.alerting.batch
package com.alexjclarke.alerting.batch
import org.springframework.boot.Banner
import org.springframework.boot.WebApplicationType
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.builder.SpringApplicationBuilder
@SpringBootApplication(scanBasePackages = ["com.poc.alerting"])
@SpringBootApplication(scanBasePackages = ["com.alexjclarke.alerting"])
open class BatchWorker
fun main(args: Array<String>) {
@@ -1,4 +1,4 @@
package com.poc.alerting.batch
package com.alexjclarke.alerting.batch
import org.apache.commons.lang3.time.DateUtils
import org.springframework.amqp.rabbit.connection.ConnectionFactory
@@ -1,7 +1,7 @@
package com.poc.alerting.batch
package com.alexjclarke.alerting.batch
import com.poc.alerting.amqp.AmqpConfiguration.Companion.NEW_ACCOUNT
import com.poc.alerting.amqp.GsonMessageConverter
import com.alexjclarke.alerting.amqp.AmqpConfiguration.Companion.NEW_ACCOUNT
import com.alexjclarke.alerting.amqp.GsonMessageConverter
import org.springframework.amqp.core.Binding
import org.springframework.amqp.core.BindingBuilder
import org.springframework.amqp.core.FanoutExchange
@@ -1,6 +1,6 @@
package com.poc.alerting.batch.jobs
package com.alexjclarke.alerting.batch.jobs
import com.poc.alerting.persistence.repositories.AlertRepository
import com.alexjclarke.alerting.persistence.repositories.AlertRepository
import org.quartz.Job
import org.quartz.JobExecutionContext
import org.springframework.beans.factory.annotation.Autowired
@@ -24,7 +24,7 @@ open class AlertQueryJob @Autowired constructor(
val cron = data.getString(CRON)
val accountId = data.getString(ACCOUNT_ID)
val alert = alertRepository.findByExtIdAndAccount_Id(alertId, accountId)
val alert = alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId)
with(alert) {
val queryResult = type.query()
@@ -1,6 +1,6 @@
package com.poc.alerting.batch.jobs
package com.alexjclarke.alerting.batch.jobs
import com.poc.alerting.batch.AutowiringSpringBeanJobFactory
import com.alexjclarke.alerting.batch.AutowiringSpringBeanJobFactory
import org.quartz.spi.JobFactory
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.context.ApplicationContext
+2 -2
View File
@@ -19,7 +19,7 @@ repositories {
}
allprojects {
group = "com.poc.alerting"
group = "com.alexjclarke.alerting"
version = "0.0.1-SNAPSHOT"
tasks.withType<JavaCompile> {
@@ -71,5 +71,5 @@ subprojects {
}
springBoot {
mainClass.set("com.poc.alerting.persistence.Persistence")
mainClass.set("com.alexjclarke.alerting.persistence.Persistence")
}
+2 -2
View File
@@ -1,10 +1,10 @@
openapi: 3.0.1
info:
title: Alerting API
description: 'This is a POC API for a dynamic, reactive alerting system.'
description: 'This is a simple API for a dynamic, reactive alerting system (minus the notification component).'
version: 0.0.1
servers:
- url: http://localhost:8080/poc/alerting/v1
- url: http://localhost:8080/api/alerting/v1
tags:
- name: Alerts
- name: Recipients
+1 -1
View File
@@ -23,5 +23,5 @@ flyway {
tasks.getByName<BootJar>("bootJar") {
enabled = true
mainClass.set("com.poc.alerting.persistence.Persistence")
mainClass.set("com.alexjclarke.alerting.persistence.Persistence")
}
@@ -1,4 +1,4 @@
package com.poc.alerting.persistence
package com.alexjclarke.alerting.persistence
import org.h2.tools.Server
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -9,8 +9,8 @@ import org.springframework.context.annotation.Profile
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
@Configuration
@EnableJpaRepositories("com.poc.alerting.persistence.repositories")
@EntityScan("com.poc.alerting.persistence.dto")
@EnableJpaRepositories("com.alexjclarke.alerting.persistence.repositories")
@EntityScan("com.alexjclarke.alerting.persistence.dto")
@EnableAutoConfiguration
open class H2Config {
@Bean(initMethod = "start", destroyMethod = "stop")
@@ -1,10 +1,10 @@
package com.poc.alerting.persistence
package com.alexjclarke.alerting.persistence
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication(scanBasePackages = ["com.poc.alerting.persistence"])
@SpringBootApplication(scanBasePackages = ["com.alexjclarke.alerting.persistence"])
open class Persistence
fun main(args: Array<String>) {
@@ -1,4 +1,4 @@
package com.poc.alerting.persistence.dto
package com.alexjclarke.alerting.persistence.dto
import javax.persistence.Entity
import javax.persistence.GeneratedValue
@@ -1,4 +1,4 @@
package com.poc.alerting.persistence.dto
package com.alexjclarke.alerting.persistence.dto
import org.hibernate.annotations.CreationTimestamp
import org.hibernate.annotations.UpdateTimestamp
@@ -1,4 +1,4 @@
package com.poc.alerting.persistence.dto
package com.alexjclarke.alerting.persistence.dto
import kotlin.random.Random
@@ -1,4 +1,4 @@
package com.poc.alerting.persistence.dto
package com.alexjclarke.alerting.persistence.dto
import org.hibernate.annotations.CreationTimestamp
import org.hibernate.annotations.UpdateTimestamp
@@ -1,4 +1,4 @@
package com.poc.alerting.persistence.dto
package com.alexjclarke.alerting.persistence.dto
enum class RecipientTypeEnum {
EMAIL,
@@ -1,6 +1,6 @@
package com.poc.alerting.persistence.repositories
package com.alexjclarke.alerting.persistence.repositories
import com.poc.alerting.persistence.dto.Account
import com.alexjclarke.alerting.persistence.dto.Account
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@@ -1,6 +1,6 @@
package com.poc.alerting.persistence.repositories
package com.alexjclarke.alerting.persistence.repositories
import com.poc.alerting.persistence.dto.Alert
import com.alexjclarke.alerting.persistence.dto.Alert
import org.springframework.data.repository.CrudRepository
import org.springframework.data.repository.PagingAndSortingRepository
import org.springframework.stereotype.Repository
@@ -1,6 +1,6 @@
package com.poc.alerting.persistence.repositories
package com.alexjclarke.alerting.persistence.repositories
import com.poc.alerting.persistence.dto.Recipient
import com.alexjclarke.alerting.persistence.dto.Recipient
import org.springframework.data.repository.CrudRepository
import org.springframework.stereotype.Repository
+1 -1
View File
@@ -1,2 +1,2 @@
rootProject.name = "alerting-poc"
rootProject.name = "alerting-api"
include(":persistence", ":amqp", ":api", ":batch")