From 7eefd7a34a880be242e9b71c6a1ca39045c2371d Mon Sep 17 00:00:00 2001
From: Pavel Kirilin <win10@list.ru>
Date: Wed, 18 Dec 2019 08:18:49 +0400
Subject: [PATCH] Added JMS support. Description: - All actions with database
 now logged throug queue. - Email sending trigger on item deletion. - Started
 update subscription mechanism.

Signed-off-by: Pavel Kirilin <win10@list.ru>
---
 docker-compose.test.yml                       | 11 ++-
 docker-compose.yml                            | 26 ++++++-
 pom.xml                                       | 16 +++++
 .../CorporateApp2Application.kt               |  3 +
 .../controllers/CinemasController.kt          |  7 +-
 .../controllers/TicketsController.kt          |  6 +-
 .../controllers/UsersController.kt            |  6 +-
 .../controllers/controllerUtils.kt            | 60 +++++++++++------
 .../controllers/rest/CinemaApiController.kt   |  6 +-
 .../rest/SubscriptionApiController.kt         | 30 +++++++++
 .../controllers/rest/TicketApiController.kt   |  8 ++-
 .../controllers/rest/UserApiController.kt     | 10 ++-
 .../rest/json/CinemasJsonController.kt        |  9 ++-
 .../rest/json/TicketsJsonController.kt        |  9 ++-
 .../rest/json/UsersJsonController.kt          |  9 ++-
 .../rest/xml/CinemasXmlController.kt          |  9 ++-
 .../rest/xml/TicketsXmlController.kt          |  9 ++-
 .../rest/xml/UsersXmlController.kt            |  9 ++-
 .../rest/xslt/CinemasXsltController.kt        | 17 +++--
 .../rest/xslt/TicketsXsltController.kt        | 21 ++++--
 .../rest/xslt/UsersXsltController.kt          | 21 ++++--
 .../com/s3ai/corporate_app2/entities.kt       |  5 +-
 .../com/s3ai/corporate_app2/jms/Config.kt     | 29 ++++++++
 .../s3ai/corporate_app2/jms/JMSPublisher.kt   | 25 +++++++
 .../s3ai/corporate_app2/jms/JmsConsumer.kt    | 60 +++++++++++++++++
 .../jms/persistance/entities.kt               | 67 +++++++++++++++++++
 .../jms/persistance/repositories.kt           | 24 +++++++
 .../jms/persistance/services.kt               |  9 +++
 .../com/s3ai/corporate_app2/repositories.kt   |  1 +
 .../com/s3ai/corporate_app2/services.kt       |  5 ++
 src/main/resources/application.properties     | 25 ++++++-
 31 files changed, 487 insertions(+), 65 deletions(-)
 create mode 100644 src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/SubscriptionApiController.kt
 create mode 100644 src/main/kotlin/com/s3ai/corporate_app2/jms/Config.kt
 create mode 100644 src/main/kotlin/com/s3ai/corporate_app2/jms/JMSPublisher.kt
 create mode 100644 src/main/kotlin/com/s3ai/corporate_app2/jms/JmsConsumer.kt
 create mode 100644 src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/entities.kt
 create mode 100644 src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/repositories.kt
 create mode 100644 src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/services.kt

diff --git a/docker-compose.test.yml b/docker-compose.test.yml
index c2d587d..9b67254 100644
--- a/docker-compose.test.yml
+++ b/docker-compose.test.yml
@@ -11,6 +11,7 @@ services:
     container_name: 'test_corporate_builder2'
     depends_on:
       - test_db
+      - test_mbroker
     working_dir: '/app'
     volumes:
       - .:/app
@@ -27,4 +28,12 @@ services:
     networks:
       test_corporate_network:
         aliases:
-          - corporate_db2
\ No newline at end of file
+          - corporate_db2
+
+  test_mbroker:
+    image: 'rmohr/activemq:5.15.9'
+    container_name: 'test_corporate_broker2'
+    networks:
+      test_corporate_network:
+        aliases:
+          - actvemq
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 09eba51..d2affb6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,5 +1,7 @@
 version: '3.7'
-
+networks:
+  corporate_app2_prod_net:
+    name: 'ca2pd'
 services:
 
   boot:
@@ -12,9 +14,10 @@ services:
     depends_on:
       - db
     working_dir: '/app'
+    networks:
+      - corporate_app2_prod_net
     volumes:
       - .:/app
-      - m2:/root/.m2
     command: >
       bash -c "/./wait-for-it.sh corporate_db2:5432 -- \
                mvn clean spring-boot:run"
@@ -31,6 +34,8 @@ services:
     image: 'postgres:10-alpine'
     container_name: 'corporate_db2'
     restart: always
+    networks:
+      - corporate_app2_prod_net
     environment:
       POSTGRES_DB: cinema
       POSTGRES_USER: postgres
@@ -40,6 +45,21 @@ services:
     volumes:
       - db_data:/var/lib/postgresql/data
 
+  mbroker:
+    image: 'rmohr/activemq:5.15.9'
+    container_name: 'corporate_broker2'
+    networks:
+      corporate_app2_prod_net:
+        aliases:
+          - actvemq
+    volumes:
+      - active_mq_data:/opt/activemq/data
+      - active_mq_conf:/opt/activemq/conf
+    ports:
+      - 8161:8161
+
 volumes:
   m2:
-  db_data:
\ No newline at end of file
+  db_data:
+  active_mq_data:
+  active_mq_conf:
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 46dd594..0284137 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,6 +32,22 @@
             <groupId>org.postgresql</groupId>
             <artifactId>postgresql</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jms</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-activemq</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.activemq</groupId>
+            <artifactId>activemq-broker</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt b/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt
index feef50d..151fdcb 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/CorporateApp2Application.kt
@@ -2,8 +2,11 @@ package com.s3ai.corporate_app2
 
 import org.springframework.boot.autoconfigure.SpringBootApplication
 import org.springframework.boot.runApplication
+import org.springframework.jms.annotation.EnableJms
+
 
 @SpringBootApplication
+@EnableJms
 class CorporateApp2Application
 
 fun main(args: Array<String>) {
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt
index 7d6f4a9..4c78ce5 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/CinemasController.kt
@@ -2,6 +2,7 @@ package com.s3ai.corporate_app2.controllers
 
 import com.s3ai.corporate_app2.Cinema
 import com.s3ai.corporate_app2.CinemaService
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Controller
 import org.springframework.ui.Model
@@ -16,6 +17,9 @@ class CinemasController {
     @Autowired
     lateinit var cinemaService: CinemaService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/list")
     fun getCinemasBrowsePage(model: Model): String? {
         model.addAttribute("cinemas", cinemaService.findAll())
@@ -27,7 +31,6 @@ class CinemasController {
         val cinema: Cinema?
         if (id.isEmpty()) {
             cinema = Cinema()
-            cinema.id = randomUUID()
             model.addAttribute("action", "Create")
         } else {
             cinema = cinemaService.findById(fromString(id))
@@ -39,7 +42,7 @@ class CinemasController {
 
     @PostMapping("/update")
     fun updateCinema(@ModelAttribute cinema: Cinema): RedirectView {
-        cinemaService.save(cinema)
+        updateItem(cinemaService, cinema, cinema.id, publisher)
         return RedirectView("/cinemas/list")
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt
index 3893625..234a961 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/TicketsController.kt
@@ -4,6 +4,7 @@ import com.s3ai.corporate_app2.CinemaService
 import com.s3ai.corporate_app2.Ticket
 import com.s3ai.corporate_app2.TicketService
 import com.s3ai.corporate_app2.UserService
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Controller
 import org.springframework.ui.Model
@@ -20,6 +21,8 @@ class TicketsController {
     lateinit var userService: UserService
     @Autowired
     lateinit var cinemaService: CinemaService
+    @Autowired
+    lateinit var publisher: JMSPublisher
 
     @GetMapping("/list")
     fun getTicketsBrowsePage(model: Model): String? {
@@ -32,7 +35,6 @@ class TicketsController {
         val ticket: Ticket?
         if (id.isEmpty()) {
             ticket = Ticket()
-            ticket.id = UUID.randomUUID()
             model.addAttribute("action", "Create")
         } else {
             ticket = ticketService.findById(UUID.fromString(id))
@@ -46,7 +48,7 @@ class TicketsController {
 
     @PostMapping("/update")
     fun updateTicket(@ModelAttribute ticket: Ticket): RedirectView {
-        ticketService.save(ticket)
+        updateItem(ticketService, ticket, ticket.id, publisher)
         return RedirectView("/tickets/list")
     }
 
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt
index 5417954..4ba2362 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/UsersController.kt
@@ -2,6 +2,7 @@ package com.s3ai.corporate_app2.controllers
 
 import com.s3ai.corporate_app2.User
 import com.s3ai.corporate_app2.UserService
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Controller
 import org.springframework.ui.Model
@@ -15,6 +16,9 @@ class UsersController {
     @Autowired
     lateinit var userService: UserService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/list")
     fun getUsersBrowsePage(model: Model): String? {
         model.addAttribute("users", userService.findAll())
@@ -38,7 +42,7 @@ class UsersController {
 
     @PostMapping("/update")
     fun updateUser(@ModelAttribute user: User): RedirectView {
-        userService.save(user)
+        updateItem(userService, user, user.id, publisher)
         return RedirectView("/users/list")
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt
index 1ae2e7b..a57aa21 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/controllerUtils.kt
@@ -2,6 +2,9 @@ package com.s3ai.corporate_app2.controllers
 
 import com.fasterxml.jackson.dataformat.xml.XmlMapper
 import com.s3ai.corporate_app2.CinemaServices
+import com.s3ai.corporate_app2.jms.JMSPublisher
+import com.s3ai.corporate_app2.jms.persistance.JMSAction
+import com.s3ai.corporate_app2.jms.persistance.JMSEntityAction
 import org.springframework.util.ResourceUtils
 import java.io.StringReader
 import java.io.StringWriter
@@ -11,16 +14,25 @@ import javax.xml.transform.TransformerFactory
 import javax.xml.transform.stream.StreamResult
 import javax.xml.transform.stream.StreamSource
 
+fun publishMessage(publisher: JMSPublisher, entity: String, actionJMS: JMSEntityAction, description: String) {
+    val jmsAction = JMSAction()
+    jmsAction.entity = entity
+    jmsAction.actionJMS = actionJMS
+    jmsAction.actionDescription = description
+    publisher.publish(jmsAction)
+}
 
-fun <T> deleteInstance(id: String, instanceName: String, jpaService: CinemaServices<T>, response: HttpServletResponse): String? {
+fun <T> deleteInstance(id: String, jpaService: CinemaServices<T>, response: HttpServletResponse, publisher: JMSPublisher): String? {
     var responseString: String? = null
     try {
         val itemId = UUID.fromString(id)
-        val user = jpaService.findById(itemId)
-        if (null != user) jpaService.delete(user)
-        else {
+        val item = jpaService.findById(itemId)
+        if (null != item) {
+            jpaService.delete(item)
+            publishMessage(publisher, jpaService.itemName(), JMSEntityAction.DELETE, "Deleted object: $item")
+        } else {
             response.status = HttpServletResponse.SC_NOT_FOUND
-            responseString = "$instanceName was not Found"
+            responseString = "${jpaService.itemName()} was not Found"
         }
     } catch (e: IllegalArgumentException) {
         response.status = HttpServletResponse.SC_BAD_REQUEST
@@ -29,14 +41,33 @@ fun <T> deleteInstance(id: String, instanceName: String, jpaService: CinemaServi
     return responseString
 }
 
-fun <T> getInstance(id: UUID, jpaService: CinemaServices<T>, response: HttpServletResponse): T? {
+fun <T : Any> getInstance(id: UUID, jpaService: CinemaServices<T>, response: HttpServletResponse, publisher: JMSPublisher): T? {
     val item = jpaService.findById(id)
-    if (null != item) return item
-    else response.status = HttpServletResponse.SC_NOT_FOUND
+    publishMessage(publisher, jpaService.itemName(), JMSEntityAction.QUERY, "Queried object with id: $id, Found: $item")
+    if (null != item) {
+        return item
+    } else response.status = HttpServletResponse.SC_NOT_FOUND
     return null
 }
 
-fun XMLTransform(item: Any, resource_name: String): String {
+fun <T : Any> getAllItems(jpaService: CinemaServices<T>, publisher: JMSPublisher): MutableList<T> {
+    val items = jpaService.findAll()
+    publishMessage(publisher, jpaService.itemName(), JMSEntityAction.QUERY, "Queried all items, found ${items.size}.")
+    return items
+}
+
+fun <T : Any> updateItem(jpaService: CinemaServices<T>, item: T, item_id: UUID?, publisher: JMSPublisher) {
+    var action = JMSEntityAction.UPDATE
+    var description = "Item id: $item_id."
+    val updatedItem = jpaService.save(item)
+    if (null == item_id) {
+        action = JMSEntityAction.CREATE
+        description = "New item data: $updatedItem"
+    }
+    publishMessage(publisher, jpaService.itemName(), action, description)
+}
+
+fun xsltTransform(item: Any, resource_name: String): String {
     val xmlMapper = XmlMapper()
     val xslt = StreamSource(ResourceUtils.getFile("classpath:xslt/$resource_name"))
     val xml = StreamSource(StringReader(xmlMapper.writeValueAsString(item)))
@@ -44,13 +75,4 @@ fun XMLTransform(item: Any, resource_name: String): String {
     val sw = StringWriter()
     transformer.transform(xml, StreamResult(sw))
     return sw.toString()
-}
-
-fun <T> getXSLTransformedInstance(id: UUID, jpaService: CinemaServices<T>, resource_name: String, response: HttpServletResponse): String {
-    val item = jpaService.findById(id)
-    if (null == item) response.status = HttpServletResponse.SC_NOT_FOUND
-    else {
-        return XMLTransform(item, resource_name)
-    }
-    return ""
-}
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt
index b734aa1..a679374 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/CinemaApiController.kt
@@ -3,6 +3,7 @@ package com.s3ai.corporate_app2.controllers.rest
 import com.s3ai.corporate_app2.Cinema
 import com.s3ai.corporate_app2.CinemaService
 import com.s3ai.corporate_app2.controllers.deleteInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.web.bind.annotation.*
 import java.util.*
@@ -15,6 +16,9 @@ class CinemaApiController {
     @Autowired
     lateinit var cinemaService: CinemaService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/fill")
     fun fillCinemas(): String? {
         val locations: List<String> = listOf("Samara", "Izhevsk", "NeoTokyo", "Bangladesh", "Moscow", "Grozny");
@@ -34,7 +38,7 @@ class CinemaApiController {
 
     @DeleteMapping("/delete")
     fun deleteCinema(@RequestParam(name = "id", required = true) id: String, response: HttpServletResponse): String? {
-        return deleteInstance(id, "Cinema", cinemaService, response)
+        return deleteInstance(id, cinemaService, response, publisher)
     }
 
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/SubscriptionApiController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/SubscriptionApiController.kt
new file mode 100644
index 0000000..10d5ccc
--- /dev/null
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/SubscriptionApiController.kt
@@ -0,0 +1,30 @@
+package com.s3ai.corporate_app2.controllers.rest
+
+import com.s3ai.corporate_app2.jms.JMSPublisher
+import com.s3ai.corporate_app2.jms.persistance.SubscribersRepository
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.web.bind.annotation.DeleteMapping
+import org.springframework.web.bind.annotation.RequestParam
+import org.springframework.web.bind.annotation.RestController
+import javax.servlet.http.HttpServletResponse
+
+@RestController
+class SubscriptionApiController {
+
+    @Autowired
+    lateinit var service: SubscribersRepository
+
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
+    @DeleteMapping("/delete")
+    fun deleteTicket(@RequestParam(name = "id", required = true) id: Long, response: HttpServletResponse): String {
+        val item = service.findById(id).orElse(null)
+        if (null != item) {
+            service.delete(item)
+            return "Deleted"
+        }
+        response.status = HttpServletResponse.SC_NOT_FOUND
+        return "Subscriber cannot be found"
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt
index d7b3711..6de73ce 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/TicketApiController.kt
@@ -5,6 +5,7 @@ import com.s3ai.corporate_app2.Ticket
 import com.s3ai.corporate_app2.TicketService
 import com.s3ai.corporate_app2.UserService
 import com.s3ai.corporate_app2.controllers.deleteInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.web.bind.annotation.*
 import java.util.*
@@ -15,11 +16,16 @@ import javax.servlet.http.HttpServletResponse
 class TicketApiController {
     @Autowired
     lateinit var userService: UserService
+
     @Autowired
     lateinit var ticketService: TicketService
+
     @Autowired
     lateinit var cinemaService: CinemaService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/fill")
     fun fillTickets(): String? {
         val wordsFirst = arrayOf("Pirates", "Ladies", "Goblins", "Gangsters", "Programmers", "Hackers", "Wrestlers", "Animals", "Guardians")
@@ -44,7 +50,7 @@ class TicketApiController {
 
     @DeleteMapping("/delete")
     fun deleteTicket(@RequestParam(name = "id", required = true) id: String, response: HttpServletResponse): String? {
-        return deleteInstance(id, "Ticket", ticketService, response)
+        return deleteInstance(id, ticketService, response, publisher)
     }
 
 }
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt
index b9a0a8c..193396c 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/UserApiController.kt
@@ -3,6 +3,7 @@ package com.s3ai.corporate_app2.controllers.rest;
 import com.s3ai.corporate_app2.User
 import com.s3ai.corporate_app2.UserService
 import com.s3ai.corporate_app2.controllers.deleteInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.web.bind.annotation.*
 import java.util.*
@@ -12,9 +13,13 @@ import kotlin.random.Random
 @RestController
 @RequestMapping("/api/users")
 class UserApiController {
+
     @Autowired
     lateinit var userService: UserService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/fill")
     fun fillCinemas(): String? {
         val names = arrayOf("Jane", "Mary", "Paul", "Jason", "Keanu", "Andrew", "Joseph", "Jotaro", "Ivan", "Jolyne", "Walther");
@@ -25,7 +30,8 @@ class UserApiController {
             user.id = UUID.randomUUID();
             user.name = "${names.random()} ${surnames.random()}";
             generatedNames.add(user.name.toString())
-            user.age = Random.nextInt(15, 70);
+            user.age = Random.nextInt(15, 70)
+
             userService.save(user);
         }
         return generatedNames.toString()
@@ -33,6 +39,6 @@ class UserApiController {
 
     @DeleteMapping("/delete")
     fun deleteUser(@RequestParam(name = "id", required = true) id: String, response: HttpServletResponse): String? {
-        return deleteInstance(id, "User", userService, response)
+        return deleteInstance(id, userService, response, publisher)
     }
 }
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt
index 033ea39..6cd1a49 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/CinemasJsonController.kt
@@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.json
 
 import com.s3ai.corporate_app2.Cinema
 import com.s3ai.corporate_app2.CinemaService
+import com.s3ai.corporate_app2.controllers.getAllItems
 import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,14 +20,17 @@ class CinemasJsonController {
     @Autowired
     lateinit var cinemaService: CinemaService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/all", produces = [MediaType.APPLICATION_JSON_VALUE])
     fun getCinemas(response: HttpServletResponse): MutableList<Cinema> {
-        return cinemaService.findAll()
+        return getAllItems(cinemaService, publisher)
     }
 
     @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
     fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): Cinema? {
-        return getInstance(id, cinemaService, response)
+        return getInstance(id, cinemaService, response, publisher)
     }
 
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt
index 12e7eec..95474bd 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/TicketsJsonController.kt
@@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.json
 
 import com.s3ai.corporate_app2.Ticket
 import com.s3ai.corporate_app2.TicketService
+import com.s3ai.corporate_app2.controllers.getAllItems
 import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,14 +20,17 @@ class TicketsJsonController {
     @Autowired
     lateinit var ticketService: TicketService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/all", produces = [MediaType.APPLICATION_JSON_VALUE])
     fun getTickets(response: HttpServletResponse): MutableList<Ticket> {
-        return ticketService.findAll()
+        return getAllItems(ticketService, publisher)
     }
 
     @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
     fun getTicket(@PathVariable id: UUID, response: HttpServletResponse): Ticket? {
-        return getInstance(id, ticketService, response)
+        return getInstance(id, ticketService, response, publisher)
     }
 
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt
index 72cb67d..a6d10f5 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/json/UsersJsonController.kt
@@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.json
 
 import com.s3ai.corporate_app2.User
 import com.s3ai.corporate_app2.UserService
+import com.s3ai.corporate_app2.controllers.getAllItems
 import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,14 +20,17 @@ class UsersJsonController {
     @Autowired
     lateinit var userService: UserService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/all", produces = [MediaType.APPLICATION_JSON_VALUE])
     fun getUsers(response: HttpServletResponse): MutableList<User> {
-        return userService.findAll()
+        return getAllItems(userService, publisher)
     }
 
     @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
     fun getUser(@PathVariable id: UUID, response: HttpServletResponse): User? {
-        return getInstance(id, userService, response)
+        return getInstance(id, userService, response, publisher)
     }
 
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt
index c566429..295c82c 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/CinemasXmlController.kt
@@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.xml
 
 import com.s3ai.corporate_app2.Cinema
 import com.s3ai.corporate_app2.CinemaService
+import com.s3ai.corporate_app2.controllers.getAllItems
 import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,14 +20,17 @@ class CinemasXmlController {
     @Autowired
     lateinit var cinemaService: CinemaService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/all", produces = [MediaType.APPLICATION_XML_VALUE])
     fun getCinemas(response: HttpServletResponse): MutableList<Cinema> {
-        return cinemaService.findAll()
+        return getAllItems(cinemaService, publisher)
     }
 
     @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_XML_VALUE])
     fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): Cinema? {
-        return getInstance(id, cinemaService, response)
+        return getInstance(id, cinemaService, response, publisher)
     }
 
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt
index ddd5b79..4648abe 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/TicketsXmlController.kt
@@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.xml
 
 import com.s3ai.corporate_app2.Ticket
 import com.s3ai.corporate_app2.TicketService
+import com.s3ai.corporate_app2.controllers.getAllItems
 import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,13 +20,16 @@ class TicketsXmlController {
     @Autowired
     lateinit var ticketService: TicketService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/all", produces = [MediaType.APPLICATION_XML_VALUE])
     fun getTickets(response: HttpServletResponse): MutableList<Ticket> {
-        return ticketService.findAll()
+        return getAllItems(ticketService, publisher)
     }
 
     @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_XML_VALUE])
     fun getTicket(@PathVariable id: UUID, response: HttpServletResponse): Ticket? {
-        return getInstance(id, ticketService, response)
+        return getInstance(id, ticketService, response, publisher)
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt
index 4de521b..cb633d5 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xml/UsersXmlController.kt
@@ -2,7 +2,9 @@ package com.s3ai.corporate_app2.controllers.rest.xml
 
 import com.s3ai.corporate_app2.User
 import com.s3ai.corporate_app2.UserService
+import com.s3ai.corporate_app2.controllers.getAllItems
 import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,13 +20,16 @@ class UsersXmlController {
     @Autowired
     lateinit var userService: UserService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     @GetMapping("/all", produces = [MediaType.APPLICATION_XML_VALUE])
     fun getUsers(response: HttpServletResponse): MutableList<User> {
-        return userService.findAll()
+        return getAllItems(userService, publisher)
     }
 
     @GetMapping("/item/{id}", produces = [MediaType.APPLICATION_XML_VALUE])
     fun getUser(@PathVariable id: UUID, response: HttpServletResponse): User? {
-        return getInstance(id, userService, response)
+        return getInstance(id, userService, response, publisher)
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt
index 498cd0a..c725379 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/CinemasXsltController.kt
@@ -1,8 +1,10 @@
 package com.s3ai.corporate_app2.controllers.rest.xslt
 
 import com.s3ai.corporate_app2.CinemaService
-import com.s3ai.corporate_app2.controllers.XMLTransform
-import com.s3ai.corporate_app2.controllers.getXSLTransformedInstance
+import com.s3ai.corporate_app2.controllers.xsltTransform
+import com.s3ai.corporate_app2.controllers.getAllItems
+import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,16 +20,23 @@ class CinemasXsltController {
     @Autowired
     lateinit var cinemaService: CinemaService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     val xsltResourceName: String = "cinema-process.xslt"
 
     @GetMapping("/all", produces = [MediaType.TEXT_HTML_VALUE])
     fun getCinemas(response: HttpServletResponse): String {
-        return XMLTransform(cinemaService.findAll(), xsltResourceName)
+        return xsltTransform(getAllItems(cinemaService, publisher), xsltResourceName)
     }
 
 
     @GetMapping("/item/{id}", produces = [MediaType.TEXT_HTML_VALUE])
     fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): String? {
-        return getXSLTransformedInstance(id, cinemaService, xsltResourceName, response)
+        val item = getInstance(id, cinemaService, response, publisher)
+        if (null != item) {
+            return xsltTransform(item, xsltResourceName)
+        }
+        return ""
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt
index 896eca4..698b878 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/TicketsXsltController.kt
@@ -1,8 +1,10 @@
 package com.s3ai.corporate_app2.controllers.rest.xslt
 
 import com.s3ai.corporate_app2.TicketService
-import com.s3ai.corporate_app2.controllers.XMLTransform
-import com.s3ai.corporate_app2.controllers.getXSLTransformedInstance
+import com.s3ai.corporate_app2.controllers.xsltTransform
+import com.s3ai.corporate_app2.controllers.getAllItems
+import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,16 +20,23 @@ class TicketsXsltController {
     @Autowired
     lateinit var ticketService: TicketService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     val xsltResourceName: String = "ticket-process.xslt"
 
     @GetMapping("/all", produces = [MediaType.TEXT_HTML_VALUE])
-    fun getCinemas(response: HttpServletResponse): String {
-        return XMLTransform(ticketService.findAll(), xsltResourceName)
+    fun getTickets(response: HttpServletResponse): String {
+        return xsltTransform(getAllItems(ticketService, publisher), xsltResourceName)
     }
 
 
     @GetMapping("/item/{id}", produces = [MediaType.TEXT_HTML_VALUE])
-    fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): String? {
-        return getXSLTransformedInstance(id, ticketService, xsltResourceName, response)
+    fun getTicket(@PathVariable id: UUID, response: HttpServletResponse): String? {
+        val item = getInstance(id, ticketService, response, publisher)
+        if (null != item) {
+            return xsltTransform(item, xsltResourceName)
+        }
+        return ""
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt
index f07ee83..c798bd4 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/controllers/rest/xslt/UsersXsltController.kt
@@ -1,8 +1,10 @@
 package com.s3ai.corporate_app2.controllers.rest.xslt
 
 import com.s3ai.corporate_app2.UserService
-import com.s3ai.corporate_app2.controllers.XMLTransform
-import com.s3ai.corporate_app2.controllers.getXSLTransformedInstance
+import com.s3ai.corporate_app2.controllers.getAllItems
+import com.s3ai.corporate_app2.controllers.getInstance
+import com.s3ai.corporate_app2.controllers.xsltTransform
+import com.s3ai.corporate_app2.jms.JMSPublisher
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.web.bind.annotation.GetMapping
@@ -18,16 +20,23 @@ class UsersXsltController {
     @Autowired
     lateinit var userService: UserService
 
+    @Autowired
+    lateinit var publisher: JMSPublisher
+
     val xsltResourceName: String = "user-process.xslt"
 
     @GetMapping("/all", produces = [MediaType.TEXT_HTML_VALUE])
-    fun getCinemas(response: HttpServletResponse): String {
-        return XMLTransform(userService.findAll(), xsltResourceName)
+    fun getUsers(response: HttpServletResponse): String {
+        return xsltTransform(getAllItems(userService, publisher), xsltResourceName)
     }
 
 
     @GetMapping("/item/{id}", produces = [MediaType.TEXT_HTML_VALUE])
-    fun getCinema(@PathVariable id: UUID, response: HttpServletResponse): String? {
-        return getXSLTransformedInstance(id, userService, xsltResourceName, response)
+    fun getUser(@PathVariable id: UUID, response: HttpServletResponse): String? {
+        val item = getInstance(id, userService, response, publisher)
+        if (null != item) {
+            return xsltTransform(item, xsltResourceName)
+        }
+        return ""
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/entities.kt b/src/main/kotlin/com/s3ai/corporate_app2/entities.kt
index 28ceb6d..e3f4d8d 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/entities.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/entities.kt
@@ -1,8 +1,6 @@
 package com.s3ai.corporate_app2
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect
-import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty
-import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement
 import org.hibernate.annotations.OnDelete
 import org.hibernate.annotations.OnDeleteAction
 import java.util.*
@@ -73,5 +71,4 @@ class Ticket {
     override fun toString(): String {
         return "Ticket{id=$id, user=$user, cinema=$cinema, movie='$movie'}"
     }
-}
-
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/Config.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/Config.kt
new file mode 100644
index 0000000..55e003c
--- /dev/null
+++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/Config.kt
@@ -0,0 +1,29 @@
+package com.s3ai.corporate_app2.jms
+
+import org.apache.activemq.ActiveMQConnectionFactory
+import org.apache.activemq.command.ActiveMQQueue
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.jms.core.JmsTemplate
+import javax.jms.Queue
+
+@Configuration
+class Config {
+    @Value("\${spring.activemq.broker-url}")
+    lateinit var brokerURL: String
+
+    @Bean
+    fun queue(): Queue = ActiveMQQueue("cinemas.queue")
+
+    @Bean
+    fun connectionFactory(): ActiveMQConnectionFactory {
+        val factory = ActiveMQConnectionFactory()
+        factory.brokerURL = brokerURL
+        return factory
+    }
+
+    @Bean
+    fun jmsTemplate(): JmsTemplate = JmsTemplate(connectionFactory())
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/JMSPublisher.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/JMSPublisher.kt
new file mode 100644
index 0000000..631df1b
--- /dev/null
+++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/JMSPublisher.kt
@@ -0,0 +1,25 @@
+package com.s3ai.corporate_app2.jms
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.s3ai.corporate_app2.jms.persistance.JMSAction
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.jms.core.JmsTemplate
+import org.springframework.stereotype.Component
+import javax.jms.Queue
+
+@Component
+class JMSPublisher {
+    @Autowired
+    private lateinit var jmsTemplate: JmsTemplate
+
+
+    @Autowired
+    private lateinit var queue: Queue
+
+    private final val mapper: ObjectMapper = ObjectMapper()
+
+    fun publish(message_obj: JMSAction) {
+        val messageText = mapper.writeValueAsString(message_obj)
+        jmsTemplate.convertAndSend(queue, messageText)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/JmsConsumer.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/JmsConsumer.kt
new file mode 100644
index 0000000..60b567f
--- /dev/null
+++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/JmsConsumer.kt
@@ -0,0 +1,60 @@
+package com.s3ai.corporate_app2.jms
+
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import com.fasterxml.jackson.module.kotlin.readValue
+import com.s3ai.corporate_app2.jms.persistance.JMSAction
+import com.s3ai.corporate_app2.jms.persistance.JMSActionService
+import com.s3ai.corporate_app2.jms.persistance.JMSEntityAction
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.jms.annotation.JmsListener
+import org.springframework.mail.javamail.JavaMailSender
+import org.springframework.mail.javamail.MimeMessageHelper
+import org.springframework.messaging.MessagingException
+import org.springframework.stereotype.Component
+
+
+@Component
+class JmsConsumer {
+
+    @Value("\${target.addresses}")
+    private lateinit var targetUsers: Array<String>
+
+    @Value("\${spring.mail.username}")
+    private lateinit var sourceUser: String
+
+    @Autowired
+    private lateinit var service: JMSActionService
+
+    @Autowired
+    private lateinit var sender: JavaMailSender
+
+    private final val mapper = jacksonObjectMapper()
+
+    fun sendEmail(action: JMSAction): Boolean {
+        val message = sender.createMimeMessage()
+        val helper = MimeMessageHelper(message)
+        try {
+            helper.setFrom(sourceUser)
+            helper.setTo(targetUsers)
+            helper.setText("Entity ${action.entity} was ${action.actionJMS.str}. ${action.actionDescription}")
+            helper.setSubject("Cinemas service notification")
+            sender.send(message)
+        } catch (e: MessagingException) {
+            e.printStackTrace()
+            return false
+        }
+        return true
+
+    }
+
+    @JmsListener(destination = "cinemas.queue")
+    fun consume(action_text: String) {
+        val action: JMSAction = mapper.readValue(action_text)
+        println(action.toString())
+        if (action.actionJMS == JMSEntityAction.DELETE) {
+            action.delivered = sendEmail(action)
+        }
+        service.save(action)
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/entities.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/entities.kt
new file mode 100644
index 0000000..8e362db
--- /dev/null
+++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/entities.kt
@@ -0,0 +1,67 @@
+package com.s3ai.corporate_app2.jms.persistance
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect
+import java.util.*
+import javax.persistence.*
+
+enum class JMSEntityAction(val str: String) {
+    UPDATE("updated"),
+    QUERY("queried"),
+    CREATE("created"),
+    DELETE("deleted")
+}
+
+@Entity
+@Table(name = "jms_action")
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
+class JMSAction {
+    @Id
+    @Column(name = "ID")
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    var id: UUID? = null
+    @Enumerated(EnumType.STRING)
+    @Column(length = 8, name = "action")
+    lateinit var actionJMS: JMSEntityAction
+    @Column(name = "entity")
+    lateinit var entity: String
+    @Column(name = "description")
+    lateinit var actionDescription: String
+    @Column(name = "delivered")
+    var delivered: Boolean = true
+
+    override fun toString(): String {
+        return "JMSAction{id=$id, action=$actionJMS, entity='$entity', actionDescription='$actionDescription'}"
+    }
+}
+
+@Entity
+@Table(name = "subscriber")
+class Subscriber {
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    var id: Long? = null
+
+    @Column(name = "email")
+    lateinit var email: String
+
+    @ManyToMany
+    @JoinTable(name = "sub_type_mapping",
+            joinColumns = [JoinColumn(name = "subscriber_id", referencedColumnName = "id")],
+            inverseJoinColumns = [JoinColumn(name = "subscription_type_id", referencedColumnName = "id")])
+    var types: List<SubscriptionType> = mutableListOf()
+}
+
+@Entity
+@Table(name = "subscription_type")
+class SubscriptionType {
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    var id: Long? = null
+
+    @Enumerated(EnumType.STRING)
+    @Column(length = 8, name = "type")
+    lateinit var type: JMSEntityAction
+
+    @ManyToMany(mappedBy = "types")
+    var subscribers: List<Subscriber> = mutableListOf()
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/repositories.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/repositories.kt
new file mode 100644
index 0000000..2117af3
--- /dev/null
+++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/repositories.kt
@@ -0,0 +1,24 @@
+package com.s3ai.corporate_app2.jms.persistance
+
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.data.jpa.repository.Query
+import org.springframework.data.repository.query.Param
+import org.springframework.stereotype.Repository
+import java.util.*
+
+@Repository
+interface JMSActionRepository : JpaRepository<JMSAction, UUID> {
+    @Query(value = "SELECT * FROM public.jms_action WHERE delivered = FALSE", nativeQuery = true)
+    fun findUndelivered(): MutableList<JMSAction>
+}
+
+@Repository
+interface SubscribersRepository : JpaRepository<Subscriber, Long> {
+
+}
+
+@Repository
+interface SubscriptionTypeRepository : JpaRepository<SubscriptionType, Long> {
+    @Query("FROM SubscriptionType WHERE type = :type")
+    fun selectByType(@Param("type") type: JMSEntityAction): List<SubscriptionType>
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/services.kt b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/services.kt
new file mode 100644
index 0000000..7683ad4
--- /dev/null
+++ b/src/main/kotlin/com/s3ai/corporate_app2/jms/persistance/services.kt
@@ -0,0 +1,9 @@
+package com.s3ai.corporate_app2.jms.persistance
+
+import org.springframework.stereotype.Service
+
+@Service
+class JMSActionService(private val jmsActionRepository: JMSActionRepository) {
+    fun save(item: JMSAction): JMSAction = jmsActionRepository.save(item)
+}
+
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt b/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt
index 6077d0a..3eed32f 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/repositories.kt
@@ -1,6 +1,7 @@
 package com.s3ai.corporate_app2
 
 import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.data.jpa.repository.Query
 import org.springframework.stereotype.Repository
 import java.util.*
 
diff --git a/src/main/kotlin/com/s3ai/corporate_app2/services.kt b/src/main/kotlin/com/s3ai/corporate_app2/services.kt
index 51cf0fb..0f51ab0 100644
--- a/src/main/kotlin/com/s3ai/corporate_app2/services.kt
+++ b/src/main/kotlin/com/s3ai/corporate_app2/services.kt
@@ -1,5 +1,6 @@
 package com.s3ai.corporate_app2
 
+import org.springframework.data.jpa.repository.Query
 import org.springframework.stereotype.Service
 import java.util.*
 
@@ -9,6 +10,7 @@ interface CinemaServices<T> {
     fun findById(id: UUID): T?
     fun save(item: T): T
     fun delete(item: T)
+    fun itemName(): String
 }
 
 @Service
@@ -17,6 +19,7 @@ class CinemaService(private val cinemaRepository: CinemaRepository) : CinemaServ
     override fun findById(id: UUID): Cinema? = cinemaRepository.findById(id).orElse(null)
     override fun save(item: Cinema): Cinema = cinemaRepository.save(item)
     override fun delete(item: Cinema) = cinemaRepository.delete(item)
+    override fun itemName(): String = "Cinema"
 }
 
 @Service
@@ -25,6 +28,7 @@ class UserService(private val userRepository: UserRepository) : CinemaServices<U
     override fun findById(id: UUID): User? = userRepository.findById(id).orElse(null)
     override fun save(item: User): User = userRepository.save(item)
     override fun delete(item: User) = userRepository.delete(item)
+    override fun itemName(): String = "User"
 }
 
 @Service
@@ -33,4 +37,5 @@ class TicketService(private val ticketRepository: TicketRepository) : CinemaServ
     override fun findById(id: UUID): Ticket? = ticketRepository.findById(id).orElse(null)
     override fun save(item: Ticket): Ticket = ticketRepository.save(item)
     override fun delete(item: Ticket) = ticketRepository.delete(item)
+    override fun itemName(): String = "Ticket"
 }
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 2b04674..594c248 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,10 +1,33 @@
 spring.thymeleaf.cache=false
+
 spring.datasource.driver-class-name=org.postgresql.Driver
 spring.datasource.url=jdbc:postgresql://corporate_db2:5432/cinema
 spring.datasource.username=postgres
 spring.datasource.password=postgres
 spring.datasource.platform=postgres
+
 spring.jpa.hibernate.ddl-auto=update
 spring.jpa.database=postgresql
 spring.jpa.database-platform=postgres
-spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect
\ No newline at end of file
+spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect
+
+spring.activemq.in-memory=false
+spring.activemq.pool.enabled=true
+spring.activemq.broker-url=tcp://actvemq:61616
+spring.activemq.user=admin
+spring.activemq.password=admin
+
+
+spring.mail.port=465
+spring.mail.host=smtp.yandex.com
+spring.mail.username=username
+spring.mail.password=password
+
+spring.mail.properties.mail.smtp.starttls.enable=true
+spring.mail.properties.mail.smtp.auth = true
+spring.mail.properties.mail.smtp.socketFactory.port = 465
+spring.mail.properties.mail.smtp.socketFactory.class = javax.net.ssl.SSLSocketFactory
+spring.mail.properties.mail.smtp.socketFactory.fallback = false
+spring.mail.properties.mail.smtp.ssl.enable=false
+
+target.addresses=win10@list.ru,win10@mail.ru
\ No newline at end of file
-- 
GitLab