Commit 95ac8082963d7d7cccaed9f2b89eba7a902ad999
Merge branch 'persistence' into 'development'
merge persistence to development See merge request !1
Showing
28 changed files
with
1118 additions
and
4 deletions
.gitignore
| @@ -14,10 +14,13 @@ hs_err_pid* | @@ -14,10 +14,13 @@ hs_err_pid* | ||
| 14 | # Logfiles | 14 | # Logfiles |
| 15 | **.log | 15 | **.log |
| 16 | **.log.* | 16 | **.log.* |
| 17 | +docker/wildfly/volumes/logs/ | ||
| 17 | 18 | ||
| 18 | **/.DS_Store | 19 | **/.DS_Store |
| 19 | .idea | 20 | .idea |
| 20 | .gradle | 21 | .gradle |
| 21 | bht-chatbot.iml | 22 | bht-chatbot.iml |
| 23 | +BeuthBot.iml | ||
| 22 | target/ | 24 | target/ |
| 23 | build | 25 | build |
| 26 | +out |
docker/docker-compose.yml
| @@ -9,13 +9,20 @@ services: | @@ -9,13 +9,20 @@ services: | ||
| 9 | - "8080:8080" | 9 | - "8080:8080" |
| 10 | - "8787:8787" | 10 | - "8787:8787" |
| 11 | - "9990:9990" | 11 | - "9990:9990" |
| 12 | + environment: | ||
| 13 | + POSTGRES_USER: beuthbot_app | ||
| 14 | + POSTGRES_PASSWORD: VhS7WPVpdYEHYLpf | ||
| 15 | + POSTGRES_DB: beuthbot | ||
| 12 | volumes: | 16 | volumes: |
| 13 | - ./wildfly/volumes/deployments/:/opt/jboss/wildfly/standalone/deployments/ | 17 | - ./wildfly/volumes/deployments/:/opt/jboss/wildfly/standalone/deployments/ |
| 14 | - ./wildfly/volumes/logs/:/opt/jboss/wildfly/standalone/log/ | 18 | - ./wildfly/volumes/logs/:/opt/jboss/wildfly/standalone/log/ |
| 15 | - ./wildfly/volumes/conf/:/opt/jboss/wildfly/standalone/conf/ | 19 | - ./wildfly/volumes/conf/:/opt/jboss/wildfly/standalone/conf/ |
| 20 | + - ./wildfly/volumes/modules/org/postgres/main/:/opt/jboss/wildfly/modules/org/postgres/main/ | ||
| 16 | links: | 21 | links: |
| 17 | - rasa-server | 22 | - rasa-server |
| 23 | + - postgres-db | ||
| 18 | command: /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 --debug | 24 | command: /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 --debug |
| 25 | + | ||
| 19 | rasa-server: | 26 | rasa-server: |
| 20 | build: ./rasa_nlu | 27 | build: ./rasa_nlu |
| 21 | container_name: rasa_nlu | 28 | container_name: rasa_nlu |
| @@ -25,4 +32,22 @@ services: | @@ -25,4 +32,22 @@ services: | ||
| 25 | volumes: | 32 | volumes: |
| 26 | - ./rasa_nlu/volumes/data/api/:/app/data/api | 33 | - ./rasa_nlu/volumes/data/api/:/app/data/api |
| 27 | - ./rasa_nlu/volumes/logs/:/app/logs/ | 34 | - ./rasa_nlu/volumes/logs/:/app/logs/ |
| 28 | - command: python -m rasa_nlu.server -c config/chatbot_config.json --server_model_dirs=default | ||
| 29 | \ No newline at end of file | 35 | \ No newline at end of file |
| 36 | + command: python -m rasa_nlu.server -c config/chatbot_config.json --server_model_dirs=default | ||
| 37 | + | ||
| 38 | + postgres-db: | ||
| 39 | + image: postgres | ||
| 40 | + ports: | ||
| 41 | + - "5432:5432" | ||
| 42 | + command: postgres -c logging_collector=on -c log_destination=stderr -c log_directory=/logs | ||
| 43 | + environment: | ||
| 44 | + POSTGRES_USER: beuthbot_app | ||
| 45 | + POSTGRES_PASSWORD: VhS7WPVpdYEHYLpf | ||
| 46 | + POSTGRES_DB: beuthbot | ||
| 47 | + volumes: | ||
| 48 | + - ./postgres/volumes/logs:/logs | ||
| 49 | + | ||
| 50 | + adminer: | ||
| 51 | + container_name: adminer_dbmanagement | ||
| 52 | + image: adminer | ||
| 53 | + ports: | ||
| 54 | + - "8081:8080" | ||
| 30 | \ No newline at end of file | 55 | \ No newline at end of file |
docker/postgres/volumes/logs/README.md
0 → 100644
docker/wildfly/Dockerfile
| 1 | FROM jboss/wildfly:10.1.0.Final | 1 | FROM jboss/wildfly:10.1.0.Final |
| 2 | RUN /opt/jboss/wildfly/bin/add-user.sh admin Admin | 2 | RUN /opt/jboss/wildfly/bin/add-user.sh admin Admin |
| 3 | -COPY standalone.xml /opt/jboss/wildfly/standalone/configuration/standalone.xml | ||
| 4 | \ No newline at end of file | 3 | \ No newline at end of file |
| 4 | +COPY standalone.xml /opt/jboss/wildfly/standalone/configuration/standalone.xml | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +#USER root | ||
| 8 | + | ||
| 9 | +#ADD modules/org/postgres/main/postgresql-42.1.4.jar /opt/jboss/wildfly/modules/org/postgres/main/postgresql-42.1.4.jar | ||
| 10 | +#ADD modules/org/postgres/main/module.xml /opt/jboss/wildfly/modules/org/postgres/main/module.xml | ||
| 5 | \ No newline at end of file | 11 | \ No newline at end of file |
docker/wildfly/standalone.xml
| @@ -161,7 +161,7 @@ | @@ -161,7 +161,7 @@ | ||
| 161 | <managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" keepalive-time="3000"/> | 161 | <managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" hung-task-threshold="60000" keepalive-time="3000"/> |
| 162 | </managed-scheduled-executor-services> | 162 | </managed-scheduled-executor-services> |
| 163 | </concurrent> | 163 | </concurrent> |
| 164 | - <default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/ExampleDS" jms-connection-factory="java:jboss/DefaultJMSConnectionFactory" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/> | 164 | + <default-bindings context-service="java:jboss/ee/concurrency/context/default" datasource="java:jboss/datasources/PostgreSQLDS" jms-connection-factory="java:jboss/DefaultJMSConnectionFactory" managed-executor-service="java:jboss/ee/concurrency/executor/default" managed-scheduled-executor-service="java:jboss/ee/concurrency/scheduler/default" managed-thread-factory="java:jboss/ee/concurrency/factory/default"/> |
| 165 | </subsystem> | 165 | </subsystem> |
| 166 | <subsystem xmlns="urn:jboss:domain:ejb3:4.0"> | 166 | <subsystem xmlns="urn:jboss:domain:ejb3:4.0"> |
| 167 | <session-bean> | 167 | <session-bean> |
| @@ -417,6 +417,40 @@ | @@ -417,6 +417,40 @@ | ||
| 417 | <client-config name="Standard-Client-Config"/> | 417 | <client-config name="Standard-Client-Config"/> |
| 418 | </subsystem> | 418 | </subsystem> |
| 419 | <subsystem xmlns="urn:jboss:domain:weld:3.0"/> | 419 | <subsystem xmlns="urn:jboss:domain:weld:3.0"/> |
| 420 | + | ||
| 421 | + <subsystem xmlns="urn:jboss:domain:datasources:2.0"> | ||
| 422 | + <datasources> | ||
| 423 | + <datasource jta="true" jndi-name="java:jboss/datasources/PostgreSQLDS" pool-name="PostgreSQLDS" enabled="true" use-java-context="true"> | ||
| 424 | + <connection-url>jdbc:postgresql://postgres-db:5432/beuthbot</connection-url> | ||
| 425 | + <connection-property name="url">jdbc:postgresql://postgres-db:5432/beuthbot</connection-property> | ||
| 426 | + <connection-property name="databaseName">beuthbot</connection-property> | ||
| 427 | + <driver>postgresql</driver> | ||
| 428 | + <security> | ||
| 429 | + <user-name>beuthbot_app</user-name> | ||
| 430 | + <password>VhS7WPVpdYEHYLpf</password> | ||
| 431 | + </security> | ||
| 432 | + <pool> | ||
| 433 | + <min-pool-size>5</min-pool-size> | ||
| 434 | + <initial-pool-size>5</initial-pool-size> | ||
| 435 | + <max-pool-size>100</max-pool-size> | ||
| 436 | + <prefill>true</prefill> | ||
| 437 | + </pool> | ||
| 438 | + <validation> | ||
| 439 | + <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/> | ||
| 440 | + <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/> | ||
| 441 | + </validation> | ||
| 442 | + </datasource> | ||
| 443 | + | ||
| 444 | + <drivers> | ||
| 445 | + <driver name="postgresql" module="org.postgres"> | ||
| 446 | + <driver-class>org.postgresql.Driver</driver-class> | ||
| 447 | + <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class> | ||
| 448 | + <datasource-class>org.postgresql.ds.PGSimpleDataSource</datasource-class> | ||
| 449 | + </driver> | ||
| 450 | + </drivers> | ||
| 451 | + </datasources> | ||
| 452 | + </subsystem> | ||
| 453 | + | ||
| 420 | </profile> | 454 | </profile> |
| 421 | 455 | ||
| 422 | <interfaces> | 456 | <interfaces> |
docker/wildfly/volumes/modules/org/postgres/main/module.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<module xmlns="urn:jboss:module:1.1" name="org.postgres"> | ||
| 3 | + <resources> | ||
| 4 | + <!--https://jdbc.postgresql.org/download.html--> | ||
| 5 | + <resource-root path="postgresql-42.1.4.jar"/> | ||
| 6 | + </resources> | ||
| 7 | + <dependencies> | ||
| 8 | + <module name="javax.api"/> | ||
| 9 | + <module name="javax.transaction.api"/> | ||
| 10 | + <module name="javax.servlet.api" optional="true"/> | ||
| 11 | + </dependencies> | ||
| 12 | +</module> | ||
| 0 | \ No newline at end of file | 13 | \ No newline at end of file |
docker/wildfly/volumes/modules/org/postgres/main/postgresql-42.1.4.jar
0 → 100644
No preview for this file type
services/Common/build.gradle
| @@ -9,6 +9,12 @@ dependencies { | @@ -9,6 +9,12 @@ dependencies { | ||
| 9 | compile "org.jboss.spec:jboss-javaee-7.0:1.1.0.Final", | 9 | compile "org.jboss.spec:jboss-javaee-7.0:1.1.0.Final", |
| 10 | "com.google.code.gson:gson:2.8.1", | 10 | "com.google.code.gson:gson:2.8.1", |
| 11 | "org.slf4j:slf4j-api:1.7.25" | 11 | "org.slf4j:slf4j-api:1.7.25" |
| 12 | + | ||
| 13 | + compile group: 'org.postgresql', name: 'postgresql', version: '9.3-1100-jdbc4' | ||
| 14 | + compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.0.1' | ||
| 15 | + | ||
| 16 | + compileOnly group: 'org.hibernate', name: 'hibernate-core', version: '5.2.12.Final' | ||
| 17 | + compileOnly group: 'org.hibernate', name: 'hibernate-entitymanager', version: '4.3.6.Final' | ||
| 12 | } | 18 | } |
| 13 | 19 | ||
| 14 | sourceCompatibility = 1.8 | 20 | sourceCompatibility = 1.8 |
| 15 | \ No newline at end of file | 21 | \ No newline at end of file |
services/Common/src/main/java/de/bht/beuthbot/daos/AppUserDAO.java
0 → 100644
| 1 | +package de.bht.beuthbot.daos; | ||
| 2 | + | ||
| 3 | +import de.bht.beuthbot.model.entities.AppUser; | ||
| 4 | + | ||
| 5 | +import javax.ejb.Remote; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * Created by Benjamin Rühl on 19.12.2017. | ||
| 9 | + */ | ||
| 10 | +@Remote | ||
| 11 | +public interface AppUserDAO extends GenericDAO<AppUser, Long> { | ||
| 12 | + | ||
| 13 | + AppUser createUser(); | ||
| 14 | +} |
services/Common/src/main/java/de/bht/beuthbot/daos/AppUserDAOImpl.java
0 → 100644
| 1 | +package de.bht.beuthbot.daos; | ||
| 2 | + | ||
| 3 | +import de.bht.beuthbot.model.entities.AppUserImpl; | ||
| 4 | +import de.bht.beuthbot.model.entities.AppUser; | ||
| 5 | + | ||
| 6 | +import javax.ejb.Stateless; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Created by Benjamin Rühl on 19.12.2017. | ||
| 10 | + */ | ||
| 11 | +@Stateless | ||
| 12 | +public class AppUserDAOImpl extends GenericHibernateDAO<AppUser, AppUserImpl, Long> implements AppUserDAO { | ||
| 13 | + | ||
| 14 | + @Override | ||
| 15 | + public AppUser createUser() { | ||
| 16 | + return new AppUserImpl(); | ||
| 17 | + } | ||
| 18 | +} |
services/Common/src/main/java/de/bht/beuthbot/daos/GenericDAO.java
0 → 100644
| 1 | +package de.bht.beuthbot.daos; | ||
| 2 | + | ||
| 3 | +import de.bht.beuthbot.model.entities.EntityBase; | ||
| 4 | + | ||
| 5 | +import javax.ejb.Remote; | ||
| 6 | +import java.io.Serializable; | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Created by Benjamin Rühl on 19.12.2017. | ||
| 11 | + */ | ||
| 12 | +@Remote | ||
| 13 | +public interface GenericDAO<T extends EntityBase, ID extends Serializable> { | ||
| 14 | + | ||
| 15 | + T findById(ID id); | ||
| 16 | + | ||
| 17 | + List<T> findAll(); | ||
| 18 | + | ||
| 19 | + T saveOrUpdate(T entity); | ||
| 20 | + | ||
| 21 | + void delete(T entity); | ||
| 22 | +} |
services/Common/src/main/java/de/bht/beuthbot/daos/GenericHibernateDAO.java
0 → 100644
| 1 | +package de.bht.beuthbot.daos; | ||
| 2 | + | ||
| 3 | +import de.bht.beuthbot.model.entities.EntityBase; | ||
| 4 | + | ||
| 5 | +import javax.annotation.PostConstruct; | ||
| 6 | +import javax.ejb.Stateless; | ||
| 7 | +import javax.persistence.EntityManager; | ||
| 8 | +import javax.persistence.EntityManagerFactory; | ||
| 9 | +import javax.persistence.PersistenceContext; | ||
| 10 | +import javax.persistence.PersistenceUnit; | ||
| 11 | +import javax.persistence.criteria.CriteriaBuilder; | ||
| 12 | +import javax.persistence.criteria.CriteriaQuery; | ||
| 13 | +import javax.persistence.criteria.Predicate; | ||
| 14 | +import javax.persistence.criteria.Root; | ||
| 15 | +import java.io.Serializable; | ||
| 16 | +import java.lang.reflect.ParameterizedType; | ||
| 17 | +import java.util.List; | ||
| 18 | + | ||
| 19 | +/** | ||
| 20 | + * Created by Benjamin Rühl on 19.12.2017. | ||
| 21 | + * Base class for DAO implementations using hibernate for persistence. | ||
| 22 | + * Provides generic functionality for interaction with entities. | ||
| 23 | + * @param <I> Interface type of entity class | ||
| 24 | + * @param <T> Implementation type of entity class | ||
| 25 | + * @param <ID> Type of entity's primary id | ||
| 26 | + */ | ||
| 27 | +@Stateless | ||
| 28 | +public class GenericHibernateDAO<I extends EntityBase, T extends I, ID extends Serializable> implements GenericDAO<I, ID> { | ||
| 29 | + | ||
| 30 | + private Class<T> entityClass; | ||
| 31 | + | ||
| 32 | + @PersistenceUnit(unitName = "PostgresPU") | ||
| 33 | + private EntityManagerFactory entityManagerFactory; | ||
| 34 | + | ||
| 35 | + @PersistenceContext(unitName = "PostgresPU") | ||
| 36 | + private EntityManager entityManager; | ||
| 37 | + | ||
| 38 | + @SuppressWarnings("unchecked cast") | ||
| 39 | + @PostConstruct | ||
| 40 | + public void init() { | ||
| 41 | + if (entityManager == null) | ||
| 42 | + throw new RuntimeException("EntityManager must not be null"); | ||
| 43 | + | ||
| 44 | + entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1]; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public Class<T> getEntityClass() { | ||
| 48 | + return entityClass; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @Override | ||
| 52 | + public I findById(ID id) { | ||
| 53 | + return entityManager.find(getEntityClass(), id); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public List<I> findAll() { | ||
| 58 | + return findByCriteria(); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + @Override | ||
| 62 | + public I saveOrUpdate(I entity) { | ||
| 63 | + entityManager.merge(entity); | ||
| 64 | + return entity; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + @Override | ||
| 68 | + public void delete(I entity) { | ||
| 69 | + entityManager.remove(entity); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + /** | ||
| 73 | + * Use this inside subclasses as a convenience method. | ||
| 74 | + */ | ||
| 75 | + protected List<I> findByCriteria(Predicate... restrictions) { | ||
| 76 | + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); | ||
| 77 | + CriteriaQuery<T> criteria = builder.createQuery(getEntityClass()); | ||
| 78 | + Root<T> criteriaRoot = criteria.from(getEntityClass()); | ||
| 79 | + | ||
| 80 | + criteria.select(criteriaRoot); | ||
| 81 | + criteria.where(restrictions); | ||
| 82 | + | ||
| 83 | + List<T> elements = entityManager.createQuery(criteria).getResultList(); | ||
| 84 | + return (List<I>) elements; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + protected EntityManager getEntityManager() { | ||
| 88 | + return entityManager; | ||
| 89 | + } | ||
| 90 | +} |
services/Common/src/main/java/de/bht/beuthbot/model/entities/AppUser.java
0 → 100644
| 1 | +package de.bht.beuthbot.model.entities; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * Created by Benjamin Rühl on 19.11.2017. | ||
| 5 | + */ | ||
| 6 | +public interface AppUser extends EntityBase { | ||
| 7 | + | ||
| 8 | + void setFacebookUserId(String facebookUserId); | ||
| 9 | + String getFacebookUserId(); | ||
| 10 | + void setTelegramUserId(String telegramUserId); | ||
| 11 | + String getTelegramUserId(); | ||
| 12 | + <T extends Object> T getProperty(String propertyName, Class<T> propertyType); | ||
| 13 | + void setProperty(String propertyName, Object propertyValue); | ||
| 14 | +} |
services/Common/src/main/java/de/bht/beuthbot/model/entities/AppUserImpl.java
0 → 100644
| 1 | +package de.bht.beuthbot.model.entities; | ||
| 2 | + | ||
| 3 | +import de.bht.beuthbot.persistence.GenericEntityAccessFacade; | ||
| 4 | + | ||
| 5 | +import javax.persistence.CascadeType; | ||
| 6 | +import javax.persistence.Entity; | ||
| 7 | +import javax.persistence.OneToOne; | ||
| 8 | +import javax.persistence.Table; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Created by Benjamin Rühl on 19.11.2017. | ||
| 12 | + * Note: This class must not be named "User" except a different table name is provided. | ||
| 13 | + * Postgres does not support creating a table named "user". | ||
| 14 | + */ | ||
| 15 | +@Entity | ||
| 16 | +@Table | ||
| 17 | +public class AppUserImpl extends EntityBaseImpl implements AppUser { | ||
| 18 | + | ||
| 19 | + private String facebookUserId; | ||
| 20 | + | ||
| 21 | + private String telegramUserId; | ||
| 22 | + | ||
| 23 | + @OneToOne(cascade = CascadeType.ALL) | ||
| 24 | + private GenericEntity additionalData; | ||
| 25 | + | ||
| 26 | + //@Type(type = "JsonMapType") | ||
| 27 | + //private Map<String, String> additionalData = new HashMap<>(); | ||
| 28 | + | ||
| 29 | + public AppUserImpl() { | ||
| 30 | + additionalData = new GenericEntity(); | ||
| 31 | + additionalData.setName("User"); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public String getFacebookUserId() { | ||
| 36 | + return facebookUserId; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + public String getTelegramUserId() { | ||
| 41 | + return telegramUserId; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @Override | ||
| 45 | + public <T> T getProperty(String propertyName, Class<T> propertyType) { | ||
| 46 | + return GenericEntityAccessFacade.getAttribute(additionalData, propertyName, propertyType); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public void setProperty(String propertyName, Object propertyValue) { | ||
| 51 | + GenericEntityAccessFacade.setAttribute(additionalData, propertyName, propertyValue); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + //@Override | ||
| 55 | + /*public <T extends Object> T getProperty(String propertyName, Class<T> propertyType) { | ||
| 56 | + String propertyValue = additionalData.getOrDefault(propertyName, null); | ||
| 57 | + | ||
| 58 | + if (propertyValue == null) | ||
| 59 | + return null; | ||
| 60 | + | ||
| 61 | + return (T) JsonHelper.fromJson(propertyValue, propertyType); | ||
| 62 | + }*/ | ||
| 63 | + | ||
| 64 | + //@Override | ||
| 65 | + /*public void setProperty(String propertyName, Object propertyValue) { | ||
| 66 | + String valueAsJson = JsonHelper.toJson(propertyValue, propertyValue.getClass()); | ||
| 67 | + additionalData.put(propertyName, valueAsJson); | ||
| 68 | + }*/ | ||
| 69 | + | ||
| 70 | + public void setFacebookUserId(String facebookUserId) { | ||
| 71 | + this.facebookUserId = facebookUserId; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + public void setTelegramUserId(String telegramUserId) { | ||
| 75 | + this.telegramUserId = telegramUserId; | ||
| 76 | + } | ||
| 77 | +} |
services/Common/src/main/java/de/bht/beuthbot/model/entities/EntityBase.java
0 → 100644
| 1 | +package de.bht.beuthbot.model.entities; | ||
| 2 | + | ||
| 3 | +import java.io.Serializable; | ||
| 4 | +import java.util.Date; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Created by Benjamin Rühl on 19.11.2017. | ||
| 8 | + */ | ||
| 9 | +public interface EntityBase extends Serializable { | ||
| 10 | + | ||
| 11 | + Long getId(); | ||
| 12 | + | ||
| 13 | + Date getCreationDate(); | ||
| 14 | + | ||
| 15 | + Date getUpdateDate(); | ||
| 16 | +} |
services/Common/src/main/java/de/bht/beuthbot/model/entities/EntityBaseImpl.java
0 → 100644
| 1 | +package de.bht.beuthbot.model.entities; | ||
| 2 | + | ||
| 3 | +import de.bht.beuthbot.persistence.JsonMapUserType; | ||
| 4 | + | ||
| 5 | +import org.hibernate.annotations.TypeDef; | ||
| 6 | + | ||
| 7 | +import javax.persistence.*; | ||
| 8 | +import java.util.Date; | ||
| 9 | +import java.util.Objects; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * Created by Benjamin Rühl on 19.11.2017. | ||
| 13 | + */ | ||
| 14 | +@MappedSuperclass | ||
| 15 | +@Access(AccessType.FIELD) | ||
| 16 | +@TypeDef(name = "JsonMapType", typeClass = JsonMapUserType.class) | ||
| 17 | +public class EntityBaseImpl implements EntityBase { | ||
| 18 | + | ||
| 19 | + @Id | ||
| 20 | + @GeneratedValue | ||
| 21 | + protected long id; | ||
| 22 | + | ||
| 23 | + @Temporal(TemporalType.TIMESTAMP) | ||
| 24 | + protected Date creationDate; | ||
| 25 | + | ||
| 26 | + @Temporal(TemporalType.TIMESTAMP) | ||
| 27 | + protected Date updateDate; | ||
| 28 | + | ||
| 29 | + @PrePersist | ||
| 30 | + protected void onCreate() { | ||
| 31 | + creationDate = new Date(); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @PreUpdate | ||
| 35 | + protected void onUpdate() { | ||
| 36 | + this.updateDate = new Date(); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + public Long getId() { | ||
| 41 | + return null; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @Override | ||
| 45 | + public Date getCreationDate() { | ||
| 46 | + return creationDate; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public Date getUpdateDate() { | ||
| 51 | + return updateDate; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Override | ||
| 55 | + public boolean equals(Object obj) { | ||
| 56 | + if (this == obj) | ||
| 57 | + return true; | ||
| 58 | + | ||
| 59 | + if (obj == null) | ||
| 60 | + return false; | ||
| 61 | + | ||
| 62 | + if (obj.getClass() != getClass()) | ||
| 63 | + return false; | ||
| 64 | + | ||
| 65 | + EntityBaseImpl other = (EntityBaseImpl)obj; | ||
| 66 | + | ||
| 67 | + if (other.getId() == 0 && getId() == 0) | ||
| 68 | + return super.equals(obj); | ||
| 69 | + | ||
| 70 | + return Objects.equals(other.getId(), getId()); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Override | ||
| 74 | + public int hashCode(){ | ||
| 75 | + return Objects.hash(id); | ||
| 76 | + } | ||
| 77 | +} |
services/Common/src/main/java/de/bht/beuthbot/model/entities/GenericEntity.java
0 → 100644
| 1 | +package de.bht.beuthbot.model.entities; | ||
| 2 | + | ||
| 3 | +import javax.persistence.CascadeType; | ||
| 4 | +import javax.persistence.Entity; | ||
| 5 | +import javax.persistence.OneToMany; | ||
| 6 | +import javax.persistence.Table; | ||
| 7 | +import java.util.ArrayList; | ||
| 8 | +import java.util.List; | ||
| 9 | +import java.util.stream.Collectors; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * Created by Benjamin Rühl on 22.12.2017. | ||
| 13 | + * A generic container entity that holds references to a set of generic attributes which can be specified at runtime. | ||
| 14 | + * Follows the Entity-Attribute-Value model of database design. | ||
| 15 | + */ | ||
| 16 | +@Entity | ||
| 17 | +@Table | ||
| 18 | +public class GenericEntity extends EntityBaseImpl { | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * name is not mandatory, but can help to identify the entity's purpose for the developer | ||
| 22 | + */ | ||
| 23 | + private String name; | ||
| 24 | + | ||
| 25 | + @OneToMany(cascade = CascadeType.ALL) | ||
| 26 | + private List<GenericEntityAttribute> attributes = new ArrayList<>(); | ||
| 27 | + | ||
| 28 | + public String getName() { | ||
| 29 | + return name; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public void setName(String name) { | ||
| 33 | + this.name = name; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public List<GenericEntityAttribute> getAttributes() { | ||
| 37 | + return attributes; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public void setAttribute(GenericEntityAttribute attribute) { | ||
| 41 | + List<GenericEntityAttribute> existingAttributesForName = this.attributes.stream().filter(a -> a.getName().equals(attribute.getName())).collect(Collectors.toList()); | ||
| 42 | + | ||
| 43 | + if (!existingAttributesForName.isEmpty()) | ||
| 44 | + getAttributes().removeAll(existingAttributesForName); | ||
| 45 | + | ||
| 46 | + this.attributes.add(attribute); | ||
| 47 | + } | ||
| 48 | +} |
services/Common/src/main/java/de/bht/beuthbot/model/entities/GenericEntityAttribute.java
0 → 100644
| 1 | +package de.bht.beuthbot.model.entities; | ||
| 2 | + | ||
| 3 | +import javax.persistence.CascadeType; | ||
| 4 | +import javax.persistence.Entity; | ||
| 5 | +import javax.persistence.OneToMany; | ||
| 6 | +import javax.persistence.Table; | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Created by Benjamin Rühl on 22.12.2017. | ||
| 11 | + * An attribute of a generic entity that can be specified at runtime. | ||
| 12 | + * Holds a collection of generic values. | ||
| 13 | + */ | ||
| 14 | +@Entity | ||
| 15 | +@Table | ||
| 16 | +public class GenericEntityAttribute extends EntityBaseImpl { | ||
| 17 | + | ||
| 18 | + private String name; | ||
| 19 | + | ||
| 20 | + @OneToMany(cascade = CascadeType.ALL) | ||
| 21 | + private List<GenericEntityAttributeValue> values; | ||
| 22 | + | ||
| 23 | + public String getName() { | ||
| 24 | + return name; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public void setName(String name) { | ||
| 28 | + this.name = name; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public List<GenericEntityAttributeValue> getValues() { | ||
| 32 | + return values; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public void addValue(GenericEntityAttributeValue value) { | ||
| 36 | + this.values.add(value); | ||
| 37 | + } | ||
| 38 | +} |
services/Common/src/main/java/de/bht/beuthbot/model/entities/GenericEntityAttributeValue.java
0 → 100644
| 1 | +package de.bht.beuthbot.model.entities; | ||
| 2 | + | ||
| 3 | +import javax.persistence.CascadeType; | ||
| 4 | +import javax.persistence.Entity; | ||
| 5 | +import javax.persistence.OneToOne; | ||
| 6 | +import javax.persistence.Table; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Created by Benjamin Rühl on 22.12.2017. | ||
| 10 | + * The value of a generic attribute in supported data formats. | ||
| 11 | + * Supports complex nested types using a reference to a generic sub entity. | ||
| 12 | + */ | ||
| 13 | +@Entity | ||
| 14 | +@Table | ||
| 15 | +public class GenericEntityAttributeValue extends EntityBaseImpl { | ||
| 16 | + | ||
| 17 | + private Boolean valueAsBool; | ||
| 18 | + | ||
| 19 | + private Long valueAsLong; | ||
| 20 | + | ||
| 21 | + private Double valueAsDouble; | ||
| 22 | + | ||
| 23 | + private String valueAsString; | ||
| 24 | + | ||
| 25 | + @OneToOne(cascade = CascadeType.ALL) | ||
| 26 | + private GenericEntity valueAsEntity; | ||
| 27 | + | ||
| 28 | + public Boolean getValueAsBool() { | ||
| 29 | + return valueAsBool; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public void setValueAsBool(boolean valueAsBool) { | ||
| 33 | + this.valueAsBool = valueAsBool; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public Long getValueAsLong() { | ||
| 37 | + return valueAsLong; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public void setValueAsLong(long valueAsLong) { | ||
| 41 | + this.valueAsLong = valueAsLong; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public Double getValueAsDouble() { | ||
| 45 | + return valueAsDouble; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + public void setValueAsDouble(double valueAsDouble) { | ||
| 49 | + this.valueAsDouble = valueAsDouble; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + public String getValueAsString() { | ||
| 53 | + return valueAsString; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + public void setValueAsString(String valueAsString) { | ||
| 57 | + this.valueAsString = valueAsString; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + public GenericEntity getValueAsEntity() { | ||
| 61 | + return valueAsEntity; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + public void setValueAsEntity(GenericEntity valueAsEntity) { | ||
| 65 | + this.valueAsEntity = valueAsEntity; | ||
| 66 | + } | ||
| 67 | +} |
services/Common/src/main/java/de/bht/beuthbot/persistence/ExtendedPostgreSQLDialect.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | ||
| 2 | + | ||
| 3 | +import org.hibernate.dialect.PostgreSQLDialect; | ||
| 4 | + | ||
| 5 | +import java.sql.Types; | ||
| 6 | + | ||
| 7 | +public class ExtendedPostgreSQLDialect extends PostgreSQLDialect { | ||
| 8 | + | ||
| 9 | + public ExtendedPostgreSQLDialect(){ | ||
| 10 | + super(); | ||
| 11 | + registerHibernateType(Types.JAVA_OBJECT, "json"); | ||
| 12 | + | ||
| 13 | + } | ||
| 14 | +} | ||
| 0 | \ No newline at end of file | 15 | \ No newline at end of file |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityAccessFacade.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 4 | +import com.fasterxml.jackson.databind.module.SimpleModule; | ||
| 5 | + | ||
| 6 | +import de.bht.beuthbot.model.entities.GenericEntity; | ||
| 7 | +import de.bht.beuthbot.model.entities.GenericEntityAttribute; | ||
| 8 | + | ||
| 9 | +import java.io.IOException; | ||
| 10 | +import java.util.List; | ||
| 11 | +import java.util.stream.Collectors; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * Created by Benjamin Rühl on 22.12.2017. | ||
| 15 | + * Provides convenience methods for accessing GenericEntity structures | ||
| 16 | + */ | ||
| 17 | +public class GenericEntityAccessFacade { | ||
| 18 | + | ||
| 19 | + public static <T> T getAttribute(GenericEntity contextEntity, String attributeName, Class<T> attributeType) { | ||
| 20 | + List<GenericEntityAttribute> propertiesWithName = contextEntity.getAttributes().stream().filter(a -> a.getName().equals(attributeName)).limit(1).collect(Collectors.toList()); | ||
| 21 | + | ||
| 22 | + if (propertiesWithName == null || propertiesWithName.isEmpty()) | ||
| 23 | + return null; | ||
| 24 | + | ||
| 25 | + GenericEntityAttribute property = propertiesWithName.get(0); | ||
| 26 | + | ||
| 27 | + try { | ||
| 28 | + String propertyAsJson = GenericEntityJsonConverter.toJson(property); | ||
| 29 | + return (T) JsonHelper.fromJson(propertyAsJson, attributeType); | ||
| 30 | + } catch (IOException e) { | ||
| 31 | + e.printStackTrace(); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + return null; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public static void setAttribute(GenericEntity contextEntity, String attributeName, Object attributeValue) { | ||
| 38 | + String attributeValueAsJson = JsonHelper.toJson(attributeValue, attributeValue.getClass()); | ||
| 39 | + | ||
| 40 | + GenericEntityAttribute deserializedGenericAttribute = null; | ||
| 41 | + | ||
| 42 | + try { | ||
| 43 | + deserializedGenericAttribute = createGenericEntityAttributeFromJson(attributeValueAsJson); | ||
| 44 | + } catch (IOException e) { | ||
| 45 | + e.printStackTrace(); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + if (deserializedGenericAttribute == null) | ||
| 49 | + return; | ||
| 50 | + | ||
| 51 | + deserializedGenericAttribute.setName(attributeName); | ||
| 52 | + | ||
| 53 | + contextEntity.setAttribute(deserializedGenericAttribute); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + private static GenericEntityAttribute createGenericEntityAttributeFromJson(String json) throws IOException { | ||
| 57 | + ObjectMapper mapper = new ObjectMapper(); | ||
| 58 | + SimpleModule module = new SimpleModule(); | ||
| 59 | + module.addDeserializer(GenericEntity.class, new GenericEntityDeserializer()); | ||
| 60 | + module.addDeserializer(GenericEntityAttribute.class, new GenericEntityAttributeDeserializer()); | ||
| 61 | + mapper.registerModule(module); | ||
| 62 | + | ||
| 63 | + return mapper.readValue(json, GenericEntityAttribute.class); | ||
| 64 | + } | ||
| 65 | +} |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityAttributeDeserializer.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.core.JsonParser; | ||
| 4 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
| 5 | +import com.fasterxml.jackson.core.JsonToken; | ||
| 6 | +import com.fasterxml.jackson.databind.DeserializationContext; | ||
| 7 | +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; | ||
| 8 | + | ||
| 9 | +import de.bht.beuthbot.model.entities.GenericEntity; | ||
| 10 | +import de.bht.beuthbot.model.entities.GenericEntityAttribute; | ||
| 11 | +import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; | ||
| 12 | + | ||
| 13 | +import javax.naming.OperationNotSupportedException; | ||
| 14 | +import java.io.IOException; | ||
| 15 | +import java.util.ArrayList; | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Created by Benjamin Rühl on 22.12.2017. | ||
| 20 | + */ | ||
| 21 | +public class GenericEntityAttributeDeserializer extends StdDeserializer<GenericEntityAttribute> { | ||
| 22 | + | ||
| 23 | + public GenericEntityAttributeDeserializer() { | ||
| 24 | + this(GenericEntityAttribute.class); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public GenericEntityAttributeDeserializer(Class<? extends GenericEntityAttribute> t) { | ||
| 28 | + super(t); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public GenericEntityAttribute deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { | ||
| 33 | + if (jp.isClosed()) | ||
| 34 | + return null; | ||
| 35 | + | ||
| 36 | + GenericEntityAttribute deserializedAttribute = new GenericEntityAttribute(); | ||
| 37 | + | ||
| 38 | + JsonToken jsonToken = jp.getCurrentToken(); | ||
| 39 | + | ||
| 40 | + if (jsonToken.equals(JsonToken.FIELD_NAME)) { | ||
| 41 | + String fieldName = jp.getCurrentName(); | ||
| 42 | + deserializedAttribute.setName(fieldName); | ||
| 43 | + | ||
| 44 | + jsonToken = jp.nextToken(); | ||
| 45 | + | ||
| 46 | + if (jsonToken.equals(JsonToken.START_ARRAY)) { | ||
| 47 | + try { | ||
| 48 | + for (GenericEntityAttributeValue attributeValue : readAttributeValuesUntilArrayEndToken(jp, ctxt)) { | ||
| 49 | + deserializedAttribute.addValue(attributeValue); | ||
| 50 | + } | ||
| 51 | + } catch (OperationNotSupportedException e) { | ||
| 52 | + e.printStackTrace(); | ||
| 53 | + } | ||
| 54 | + } else { | ||
| 55 | + deserializedAttribute.addValue(readAttributeValueFromCurrentToken(jp, ctxt)); | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + return deserializedAttribute; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + private List<GenericEntityAttributeValue> readAttributeValuesUntilArrayEndToken(JsonParser jp, DeserializationContext ctxt) throws IOException, OperationNotSupportedException { | ||
| 63 | + List<GenericEntityAttributeValue> attributes = new ArrayList<>(); | ||
| 64 | + JsonToken jsonToken = jp.getCurrentToken(); | ||
| 65 | + | ||
| 66 | + if (!jsonToken.equals(JsonToken.START_ARRAY)) | ||
| 67 | + throw new OperationNotSupportedException("Method should not be called if current token is not START_ARRAY"); | ||
| 68 | + | ||
| 69 | + while (!jp.isClosed() || jsonToken.equals(JsonToken.END_ARRAY)) { | ||
| 70 | + jsonToken = jp.nextToken(); | ||
| 71 | + attributes.add(readAttributeValueFromCurrentToken(jp, ctxt)); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + return attributes; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + private GenericEntityAttributeValue readAttributeValueFromCurrentToken(JsonParser jp, DeserializationContext ctxt) throws IOException { | ||
| 78 | + GenericEntityAttributeValue attributeValue = new GenericEntityAttributeValue(); | ||
| 79 | + JsonToken jsonToken = jp.getCurrentToken(); | ||
| 80 | + | ||
| 81 | + if (jsonToken.equals(JsonToken.VALUE_FALSE) || jsonToken.equals(JsonToken.VALUE_TRUE)) { | ||
| 82 | + attributeValue.setValueAsBool(jp.getBooleanValue()); | ||
| 83 | + } else if (jsonToken.equals(JsonToken.VALUE_NUMBER_INT)) { | ||
| 84 | + attributeValue.setValueAsLong(jp.getLongValue()); | ||
| 85 | + } else if (jsonToken.equals(JsonToken.VALUE_NUMBER_FLOAT)) { | ||
| 86 | + attributeValue.setValueAsDouble(jp.getFloatValue()); | ||
| 87 | + } else if (jsonToken.equals(JsonToken.VALUE_STRING)) { | ||
| 88 | + attributeValue.setValueAsString(jp.getText()); | ||
| 89 | + } else if (jsonToken.equals(JsonToken.START_OBJECT)) { | ||
| 90 | + GenericEntity embeddedEntity = new GenericEntityDeserializer().deserialize(jp, ctxt); | ||
| 91 | + attributeValue.setValueAsEntity(embeddedEntity); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + return attributeValue; | ||
| 95 | + } | ||
| 96 | +} |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityDeserializer.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.core.JsonParser; | ||
| 4 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
| 5 | +import com.fasterxml.jackson.core.JsonToken; | ||
| 6 | +import com.fasterxml.jackson.databind.DeserializationContext; | ||
| 7 | +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; | ||
| 8 | + | ||
| 9 | +import de.bht.beuthbot.model.entities.GenericEntity; | ||
| 10 | +import de.bht.beuthbot.model.entities.GenericEntityAttribute; | ||
| 11 | + | ||
| 12 | +import java.io.IOException; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * Created by Benjamin Rühl on 23.12.2017. | ||
| 16 | + */ | ||
| 17 | +public class GenericEntityDeserializer extends StdDeserializer<GenericEntity> { | ||
| 18 | + | ||
| 19 | + public GenericEntityDeserializer() { | ||
| 20 | + this(GenericEntity.class); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + public GenericEntityDeserializer(Class<? extends GenericEntity> t) { | ||
| 24 | + super(t); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public GenericEntity deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { | ||
| 29 | + GenericEntity deserializedEntity = new GenericEntity(); | ||
| 30 | + GenericEntityAttributeDeserializer attributeDeserializer = new GenericEntityAttributeDeserializer(); | ||
| 31 | + | ||
| 32 | + while (!jp.isClosed()) { | ||
| 33 | + JsonToken jsonToken = jp.nextToken(); | ||
| 34 | + | ||
| 35 | + if (jsonToken.equals(JsonToken.FIELD_NAME)) { | ||
| 36 | + GenericEntityAttribute attribute = attributeDeserializer.deserialize(jp, ctxt); | ||
| 37 | + deserializedEntity.setAttribute(attribute); | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + return deserializedEntity; | ||
| 42 | + } | ||
| 43 | +} | ||
| 0 | \ No newline at end of file | 44 | \ No newline at end of file |
services/Common/src/main/java/de/bht/beuthbot/persistence/GenericEntityJsonConverter.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.core.JsonFactory; | ||
| 4 | +import com.fasterxml.jackson.core.JsonGenerator; | ||
| 5 | + | ||
| 6 | +import de.bht.beuthbot.model.entities.GenericEntity; | ||
| 7 | +import de.bht.beuthbot.model.entities.GenericEntityAttribute; | ||
| 8 | +import de.bht.beuthbot.model.entities.GenericEntityAttributeValue; | ||
| 9 | + | ||
| 10 | +import java.io.IOException; | ||
| 11 | +import java.io.StringWriter; | ||
| 12 | +import java.lang.reflect.Field; | ||
| 13 | +import java.lang.reflect.ParameterizedType; | ||
| 14 | +import java.lang.reflect.Type; | ||
| 15 | +import java.util.Arrays; | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Created by Benjamin Rühl on 22.12.2017. | ||
| 20 | + * Helper class to serialize GenericEntity as if its generic attributes were normal fields | ||
| 21 | + */ | ||
| 22 | +public class GenericEntityJsonConverter { | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * Serializes a GenericEntity to json as if its generic attributes were normal fields. | ||
| 26 | + * Other normal fields are serialized as well. | ||
| 27 | + * @param genericEntity the context entity to be serialized with all its sub structure | ||
| 28 | + * @return a serialized string in json format | ||
| 29 | + * @throws IOException | ||
| 30 | + */ | ||
| 31 | + public static String toJson(GenericEntity genericEntity) throws IOException { | ||
| 32 | + JsonFactory jFactory = new JsonFactory(); | ||
| 33 | + StringWriter writer = new StringWriter(); | ||
| 34 | + JsonGenerator jsonGenerator = jFactory.createJsonGenerator(writer); | ||
| 35 | + | ||
| 36 | + jsonGenerator.writeStartObject(); | ||
| 37 | + writeGenericEntityWithoutStart(jsonGenerator, genericEntity); | ||
| 38 | + | ||
| 39 | + jsonGenerator.close(); | ||
| 40 | + return writer.toString(); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * Serializes a GenericEntityAttribute to json as if it would be a normal field. | ||
| 45 | + * @param genericAttribute the context attribute to be serialized with all its sub structure | ||
| 46 | + * @return a serialized string in json format | ||
| 47 | + * @throws IOException | ||
| 48 | + */ | ||
| 49 | + public static String toJson(GenericEntityAttribute genericAttribute) throws IOException { | ||
| 50 | + JsonFactory jFactory = new JsonFactory(); | ||
| 51 | + StringWriter writer = new StringWriter(); | ||
| 52 | + JsonGenerator jsonGenerator = jFactory.createJsonGenerator(writer); | ||
| 53 | + | ||
| 54 | + writeGenericAttribute(jsonGenerator, genericAttribute); | ||
| 55 | + | ||
| 56 | + jsonGenerator.close(); | ||
| 57 | + return writer.toString(); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * Uses a JsonGenerator to append a GenericEntity and its content to json. | ||
| 62 | + * Does not open the json object because this part depends on whether the object stands for itself or is the value of a field. | ||
| 63 | + * However it does close the object. | ||
| 64 | + * @param jsonGenerator the generator used for building the json | ||
| 65 | + * @param genericEntity the context entity that is serialized | ||
| 66 | + * @throws IOException | ||
| 67 | + */ | ||
| 68 | + private static void writeGenericEntityWithoutStart(JsonGenerator jsonGenerator, GenericEntity genericEntity) throws IOException { | ||
| 69 | + writeClassFieldsWithoutGenericEntityHierarchy(jsonGenerator, genericEntity); | ||
| 70 | + | ||
| 71 | + for (GenericEntityAttribute genericAttribute : genericEntity.getAttributes()) { | ||
| 72 | + writeGenericAttribute(jsonGenerator, genericAttribute); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + jsonGenerator.writeEndObject(); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + private static void writeGenericAttribute(JsonGenerator jsonGenerator, GenericEntityAttribute genericAttribute) throws IOException { | ||
| 79 | + List<GenericEntityAttributeValue> attributeValues = genericAttribute.getValues(); | ||
| 80 | + | ||
| 81 | + if (attributeValues == null || attributeValues.isEmpty()) { | ||
| 82 | + jsonGenerator.writeNullField(genericAttribute.getName()); | ||
| 83 | + } else if (attributeValues.size() == 1) { | ||
| 84 | + writeGenericAttributeValue(jsonGenerator, genericAttribute.getValues().get(0), genericAttribute.getName()); | ||
| 85 | + } else { | ||
| 86 | + writeGenericAttributeMultiValue(jsonGenerator, genericAttribute); | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + private static void writeGenericAttributeMultiValue(JsonGenerator jsonGenerator, GenericEntityAttribute genericAttribute) throws IOException { | ||
| 91 | + jsonGenerator.writeArrayFieldStart(genericAttribute.getName()); | ||
| 92 | + | ||
| 93 | + for (GenericEntityAttributeValue genericValue : genericAttribute.getValues()) { | ||
| 94 | + writeGenericAttributeValueInArray(jsonGenerator, genericValue); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + jsonGenerator.writeEndArray(); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + private static void writeGenericAttributeValue(JsonGenerator jsonGenerator, GenericEntityAttributeValue genericAttributeValue, String attributeName) throws IOException { | ||
| 101 | + if (genericAttributeValue.getValueAsBool() != null) { | ||
| 102 | + jsonGenerator.writeBooleanField(attributeName, genericAttributeValue.getValueAsBool()); | ||
| 103 | + } else if (genericAttributeValue.getValueAsLong() != null) { | ||
| 104 | + jsonGenerator.writeNumberField(attributeName, genericAttributeValue.getValueAsLong()); | ||
| 105 | + } else if (genericAttributeValue.getValueAsDouble() != null) { | ||
| 106 | + jsonGenerator.writeNumberField(attributeName, genericAttributeValue.getValueAsDouble()); | ||
| 107 | + } else if (genericAttributeValue.getValueAsString() != null) { | ||
| 108 | + jsonGenerator.writeStringField(attributeName, genericAttributeValue.getValueAsString()); | ||
| 109 | + } else if (genericAttributeValue.getValueAsEntity() != null) { | ||
| 110 | + jsonGenerator.writeObjectFieldStart(attributeName); | ||
| 111 | + writeGenericEntityWithoutStart(jsonGenerator, genericAttributeValue.getValueAsEntity()); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + private static void writeGenericAttributeValueInArray(JsonGenerator jsonGenerator, GenericEntityAttributeValue genericAttributeValue) throws IOException { | ||
| 116 | + if (genericAttributeValue.getValueAsBool() != null) { | ||
| 117 | + jsonGenerator.writeBoolean(genericAttributeValue.getValueAsBool()); | ||
| 118 | + } else if (genericAttributeValue.getValueAsLong() != null) { | ||
| 119 | + jsonGenerator.writeNumber(genericAttributeValue.getValueAsLong()); | ||
| 120 | + } else if (genericAttributeValue.getValueAsDouble() != null) { | ||
| 121 | + jsonGenerator.writeNumber(genericAttributeValue.getValueAsDouble()); | ||
| 122 | + } else if (genericAttributeValue.getValueAsString() != null) { | ||
| 123 | + jsonGenerator.writeString(genericAttributeValue.getValueAsString()); | ||
| 124 | + } else if (genericAttributeValue.getValueAsEntity() != null) { | ||
| 125 | + jsonGenerator.writeStartObject(); | ||
| 126 | + writeGenericEntityWithoutStart(jsonGenerator, genericAttributeValue.getValueAsEntity()); | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * Uses a JsonGenerator to append all fields and their values of the targetObject to json. | ||
| 132 | + * Ignores fields that have GenericEntity, GenericEntityAttribute or GenericEntityAttributeValue as type or generic list parameter. | ||
| 133 | + * @throws IOException | ||
| 134 | + */ | ||
| 135 | + private static void writeClassFieldsWithoutGenericEntityHierarchy(JsonGenerator jsonGenerator, Object targetObject) throws IOException { | ||
| 136 | + for (Field field : targetObject.getClass().getFields()) { | ||
| 137 | + if (isGenericEntityHierarchyType(field)) | ||
| 138 | + continue; | ||
| 139 | + | ||
| 140 | + try { | ||
| 141 | + jsonGenerator.writeObjectField(field.getName(), field.get(targetObject)); | ||
| 142 | + } catch (Exception e) { | ||
| 143 | + jsonGenerator.writeStringField(field.getName(), e.getClass().getName()); | ||
| 144 | + e.printStackTrace(); | ||
| 145 | + } | ||
| 146 | + } | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + /** | ||
| 150 | + * Determines whether the field's type is GenericEntity, GenericEntityAttribute or GenericEntityAttributeValue | ||
| 151 | + * or a list type with one of those types as generic type parameter. | ||
| 152 | + */ | ||
| 153 | + private static boolean isGenericEntityHierarchyType(Field field) { | ||
| 154 | + List<Class> typesOfGenericEntityHierarchy = Arrays.asList(GenericEntity.class, GenericEntityAttribute.class, GenericEntityAttributeValue.class); | ||
| 155 | + | ||
| 156 | + // check for list types | ||
| 157 | + try { | ||
| 158 | + if (Iterable.class.isAssignableFrom(field.getType())) { | ||
| 159 | + Type fieldFirstGenericType = ((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]; | ||
| 160 | + if (typesOfGenericEntityHierarchy.contains(fieldFirstGenericType.getClass())) | ||
| 161 | + return true; | ||
| 162 | + } | ||
| 163 | + } catch (Exception e) { | ||
| 164 | + // not a list or not generic | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + return typesOfGenericEntityHierarchy.contains(field.getType()); | ||
| 168 | + } | ||
| 169 | +} |
services/Common/src/main/java/de/bht/beuthbot/persistence/JsonHelper.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | ||
| 2 | + | ||
| 3 | +import com.google.gson.Gson; | ||
| 4 | +import com.google.gson.GsonBuilder; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * Created by Benjamin Rühl on 03.12.2017. | ||
| 8 | + * A simple wrapper around the json serializer to make sure the same serializer is used across different classes | ||
| 9 | + */ | ||
| 10 | +public class JsonHelper { | ||
| 11 | + | ||
| 12 | + private static final Gson gson = new GsonBuilder().serializeNulls().create(); | ||
| 13 | + | ||
| 14 | + public static Object fromJson(String json, Class sourceClass) { | ||
| 15 | + return gson.fromJson(json, sourceClass); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + public static String toJson(Object source, Class sourceClass) { | ||
| 19 | + return gson.toJson(source, sourceClass); | ||
| 20 | + } | ||
| 21 | +} |
services/Common/src/main/java/de/bht/beuthbot/persistence/JsonMapUserType.java
0 → 100644
| 1 | +package de.bht.beuthbot.persistence; | ||
| 2 | + | ||
| 3 | +import org.hibernate.HibernateException; | ||
| 4 | +import org.hibernate.engine.spi.SharedSessionContractImplementor; | ||
| 5 | +import org.hibernate.internal.util.compare.EqualsHelper; | ||
| 6 | +import org.hibernate.type.SerializationException; | ||
| 7 | +import org.hibernate.usertype.UserType; | ||
| 8 | +import org.postgresql.util.PGobject; | ||
| 9 | + | ||
| 10 | +import java.io.Serializable; | ||
| 11 | +import java.sql.PreparedStatement; | ||
| 12 | +import java.sql.ResultSet; | ||
| 13 | +import java.sql.SQLException; | ||
| 14 | +import java.sql.Types; | ||
| 15 | +import java.util.HashMap; | ||
| 16 | +import java.util.Map; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Created by Benjamin Rühl on 03.12.2017. | ||
| 20 | + * Custom Hibernate UserType for mapping json typed columns in postgres to java maps | ||
| 21 | + * @see <a href="http://vojtechruzicka.com/postgresqls-jsonb-type-mapping-using-hibernate/">vojtechruzicka.com</a> | ||
| 22 | + */ | ||
| 23 | +public class JsonMapUserType implements UserType { | ||
| 24 | + | ||
| 25 | + @Override | ||
| 26 | + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException { | ||
| 27 | + if (value == null) { | ||
| 28 | + st.setNull(index, Types.OTHER); | ||
| 29 | + } else { | ||
| 30 | + st.setObject(index, JsonHelper.toJson(value, Map.class), Types.OTHER); | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException { | ||
| 36 | + PGobject o = (PGobject) rs.getObject(names[0]); | ||
| 37 | + if (o.getValue() != null) { | ||
| 38 | + return JsonHelper.fromJson(o.getValue(), Map.class); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + return new HashMap<String, String>(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @Override | ||
| 45 | + public Object deepCopy(Object originalValue) throws HibernateException { | ||
| 46 | + if (originalValue == null) { | ||
| 47 | + return null; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + if (!(originalValue instanceof Map)) { | ||
| 51 | + return null; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + Map<String, String> resultMap = new HashMap<>(); | ||
| 55 | + | ||
| 56 | + Map<?, ?> tempMap = (Map<?, ?>) originalValue; | ||
| 57 | + tempMap.forEach((key, value) -> resultMap.put((String) key, (String) value)); | ||
| 58 | + | ||
| 59 | + return resultMap; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public Serializable disassemble(Object value) throws HibernateException { | ||
| 64 | + Object copy = deepCopy(value); | ||
| 65 | + | ||
| 66 | + if (copy instanceof Serializable) { | ||
| 67 | + return (Serializable) copy; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + throw new SerializationException(String.format("Cannot serialize '%s', %s is not Serializable.", value, value.getClass()), null); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Override | ||
| 74 | + public Object assemble(Serializable cached, Object owner) throws HibernateException { | ||
| 75 | + return deepCopy(cached); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + @Override | ||
| 79 | + public Object replace(Object original, Object target, Object owner) throws HibernateException { | ||
| 80 | + return deepCopy(original); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @Override | ||
| 84 | + public boolean isMutable() { | ||
| 85 | + return true; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + @Override | ||
| 89 | + public int hashCode(Object x) throws HibernateException { | ||
| 90 | + if (x == null) { | ||
| 91 | + return 0; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + return x.hashCode(); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + @Override | ||
| 98 | + public boolean equals(Object x, Object y) throws HibernateException { | ||
| 99 | + return EqualsHelper.equals(x, y); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + @Override | ||
| 103 | + public Class<?> returnedClass() { | ||
| 104 | + return Map.class; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + public int[] sqlTypes() { | ||
| 109 | + return new int[]{Types.JAVA_OBJECT}; | ||
| 110 | + } | ||
| 111 | +} |
services/Common/src/main/resources/META-INF/persistence.xml
0 → 100644
| 1 | +<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" | ||
| 2 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 3 | + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence | ||
| 4 | + http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" | ||
| 5 | + version="2.1"> | ||
| 6 | + | ||
| 7 | + <persistence-unit name="PostgresPU" transaction-type="JTA"> | ||
| 8 | + | ||
| 9 | + <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> | ||
| 10 | + | ||
| 11 | + <jta-data-source>java:jboss/datasources/PostgreSQLDS</jta-data-source> | ||
| 12 | + | ||
| 13 | + <properties> | ||
| 14 | + | ||
| 15 | + <!--<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>--> <!-- DB Dialect --> | ||
| 16 | + <property name="hibernate.dialect" value="de.bht.beuthbot.persistence.ExtendedPostgreSQLDialect"/> | ||
| 17 | + <!--<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>--> | ||
| 18 | + <property name="hibernate.hbm2ddl.auto" value="create-drop" /> <!-- create / create-drop / update / none --> | ||
| 19 | + <property name="hibernate.archive.autodetection" value="class"/> | ||
| 20 | + | ||
| 21 | + <property name="hibernate.show_sql" value="true" /> <!-- Show SQL in console --> | ||
| 22 | + <property name="hibernate.format_sql" value="true" /> <!-- Show SQL formatted --> | ||
| 23 | + </properties> | ||
| 24 | + | ||
| 25 | + </persistence-unit> | ||
| 26 | + | ||
| 27 | +</persistence> | ||
| 0 | \ No newline at end of file | 28 | \ No newline at end of file |
services/Global/build.gradle
| @@ -13,7 +13,6 @@ dependencies { | @@ -13,7 +13,6 @@ dependencies { | ||
| 13 | "org.apache.httpcomponents:httpclient:4.5.3", | 13 | "org.apache.httpcomponents:httpclient:4.5.3", |
| 14 | "commons-io:commons-io:2.5" | 14 | "commons-io:commons-io:2.5" |
| 15 | 15 | ||
| 16 | - | ||
| 17 | providedCompile "org.slf4j:slf4j-api:1.7.25" | 16 | providedCompile "org.slf4j:slf4j-api:1.7.25" |
| 18 | 17 | ||
| 19 | testCompile "org.jboss.arquillian.junit:arquillian-junit-container:1.1.13.Final", | 18 | testCompile "org.jboss.arquillian.junit:arquillian-junit-container:1.1.13.Final", |