Compare commits
228 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 70302edc58 | |||
| fb1b3001ac | |||
| 9297be25d6 | |||
| ddeedfb3ad | |||
| 3b4c214e3f | |||
| 081af716d1 | |||
| 84ed78bcef | |||
| 1d8ff8b02e | |||
| ffaf9a16c5 | |||
| 698ddfd199 | |||
| ec82f06f88 | |||
| d427956422 | |||
| e82a4cadd4 | |||
| 84b8b0545f | |||
| cd2e3b0642 | |||
| b129228b36 | |||
| 57907d05e6 | |||
| c983bde031 | |||
| 0e21c9baf7 | |||
| e12127f6dd | |||
| 9090b2c66e | |||
| 799c7d52e3 | |||
| 6d9a87e15b | |||
| 4dddc1f3dc | |||
| b4a28bb0b0 | |||
| d5dc39e8ff | |||
| 233164fb54 | |||
| bea1d80f1e | |||
| 571386046d | |||
| 103b8348d0 | |||
| 06fe2231ec | |||
| 113cb4a641 | |||
| 6d49dec89f | |||
| ee1a20836d | |||
| 626ab1b528 | |||
| aeab3a5ca9 | |||
| a2430f748f | |||
| af298c8060 | |||
| 6348f81bed | |||
| 13d16a1309 | |||
| 585b6d7d02 | |||
| a071cb5732 | |||
| f804c11ceb | |||
| 218d7a7365 | |||
| 2128ad95bc | |||
| 53991b7f56 | |||
| 59420af4a5 | |||
| fe8b0d272b | |||
| 89ddbbdbb2 | |||
| c4d71f9614 | |||
| 97649c9306 | |||
| 0cbab859f8 | |||
| eb3bf3b71a | |||
| b138841faa | |||
| 5a840dad7f | |||
| 0f98586434 | |||
| 08a0adcc6f | |||
| 8205ffaec3 | |||
| 54f2e56a4c | |||
| 119fb04520 | |||
| 24dc927ab7 | |||
| 3ae4dba8fe | |||
| bf590223b8 | |||
| 1e5e15cda0 | |||
| 40acbcd6ac | |||
| ab2a0e2301 | |||
| a8e0f9bd5f | |||
| 88d2509893 | |||
| 96892cf8f9 | |||
| 6829b65a2f | |||
| a9e136d3ac | |||
| aa478dbf9f | |||
| 2a75d2a1fe | |||
| a8a609491f | |||
| 43f5401773 | |||
| e9dede69cb | |||
| 7a380dc214 | |||
| 212e4dad5d | |||
| d50f21f869 | |||
| cf433524cd | |||
| a64051dc28 | |||
| 91f8c2b2f1 | |||
| 7161c32a61 | |||
| be34fa9e8d | |||
| 4ec319fc45 | |||
| bb3d08360e | |||
| 336e76f536 | |||
| 70a45b1919 | |||
| 59969ccef4 | |||
| 4f3c3d4673 | |||
| 70829f9204 | |||
| 91b967f008 | |||
| eb332461aa | |||
| 4fd1710503 | |||
| 3d1f2a93cf | |||
| f8fe805ba6 | |||
| cc7e1b5e73 | |||
| 4aafdb1222 | |||
| cdc5a2ae8c | |||
| b49fb0e19d | |||
| e75523e9dd | |||
| 0d0984bb53 | |||
| 827b110e7c | |||
| 701f0dd3a0 | |||
| a7e845d514 | |||
| 7b315f6fd0 | |||
| 70bebd4ef8 | |||
| d76154e279 | |||
| b30b40769c | |||
| be31b12d0a | |||
| 03281643ad | |||
| 6117cc6c10 | |||
| 479145af6f | |||
| b32b756da1 | |||
| 1c6bb1769c | |||
| 6933900635 | |||
| 763d6f57f2 | |||
| 2540d2a454 | |||
| 76795365c0 | |||
| 5c7abf4c47 | |||
| a3e7f6c527 | |||
| 73bb6a18ca | |||
| 15dc1f9e50 | |||
| 825aa6cbf5 | |||
| 9f301136f0 | |||
| 4daa43ad04 | |||
| 5ab4d99dd3 | |||
| 333508632c | |||
| 38592887c5 | |||
| 49e0c9651e | |||
| ac2cf1b784 | |||
| 584bdfce4f | |||
| 48a6ca9231 | |||
| 37290a2ed7 | |||
| 3ba593a15c | |||
| c1410554f5 | |||
| dc2ec093d2 | |||
| 1aab667a8e | |||
| 2659ba1ff5 | |||
| 2965c6be4b | |||
| 7790a6fe50 | |||
| 12da8c2d8c | |||
| 698b4477a2 | |||
| 8291d3e3aa | |||
| ecedc1872b | |||
| b552e0b8bc | |||
| f4145ca2fc | |||
| e114dcb9eb | |||
| 257def9140 | |||
| d8e47d1eb0 | |||
| df86b707a6 | |||
| c3fafa4331 | |||
| 0b123bec0f | |||
| 452ffa4f9d | |||
| aaa67135a8 | |||
| 7acc23892b | |||
| 6bad0e75a6 | |||
| 7ad25dc734 | |||
| 5e42012907 | |||
| c09a27583b | |||
| 1fed967100 | |||
| 87f389fc2d | |||
| 057dfd9c05 | |||
| f712e269c5 | |||
| 350d045eb0 | |||
| 9b8284a2cf | |||
| ac39be3848 | |||
| 0b044bac78 | |||
| c05ba11044 | |||
| 79c9ab623c | |||
| 8c11d3424e | |||
| c822b30ca0 | |||
| ed0892b1dc | |||
| 06d625013b | |||
| 4f6f851e2b | |||
| 798a178f42 | |||
| 1e3d2986c5 | |||
| 4d69e8e70a | |||
| 46f2827338 | |||
| b2c2619dc4 | |||
| 349310ccf9 | |||
| 1bb9b24bcf | |||
| 2dc317b84f | |||
| 7b1d4f24ab | |||
| 389e3a6a73 | |||
| 6f5baaaa69 | |||
| 6533451d06 | |||
| 765589afdf | |||
| 939f043b01 | |||
| ed63692c0c | |||
| 13da4a3e04 | |||
| 7fceccc109 | |||
| 00925aa389 | |||
| 76114f6cf2 | |||
| d1f72db6ac | |||
| ea3ebdddf5 | |||
| c5a70b9d11 | |||
| 634b51b051 | |||
| 17c080faa2 | |||
| 9ebb649458 | |||
| c30af64604 | |||
| c254d27e84 | |||
| b95ffdb417 | |||
| 14e4c2cc6e | |||
| f07467fd3e | |||
| 4eb6bb77e2 | |||
| 8c4f304d18 | |||
| d3e0e09718 | |||
| 95d93ec222 | |||
| 4d79cbc35b | |||
| 530b6f500a | |||
| 8b2da09418 | |||
| 64c5d3b370 | |||
| c3961f9a28 | |||
| 65cdf950c9 | |||
| ecf8558e92 | |||
| 81cd34817b | |||
| a0cda5f498 | |||
| 4b2e4e9055 | |||
| a0d77ca744 | |||
| 9da7004c6b | |||
| 0a47471b49 | |||
| 4559f20170 | |||
| 077ab22438 | |||
| da46ca4c16 | |||
| a68f19b868 | |||
| 6a05de2b30 | |||
| 1feb529c9e |
1154
.editorconfig
Normal file
1154
.editorconfig
Normal file
File diff suppressed because it is too large
Load Diff
201
.gitignore
vendored
201
.gitignore
vendored
@ -1,10 +1,191 @@
|
||||
/configuration/target/
|
||||
/network/target/
|
||||
/util/target/
|
||||
/sharepoint/api/target/
|
||||
/security/target/
|
||||
/jeeutil/target/
|
||||
/account/target/
|
||||
/shiro-faces/target/
|
||||
/pdf/target/
|
||||
/shared-poi-util/target/
|
||||
# ---> NetBeans
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
nbactions.xml
|
||||
**/nb-configuration.xml
|
||||
.nb-gradle/
|
||||
**/faces-config.NavData
|
||||
|
||||
# ---> Eclipse
|
||||
.project
|
||||
.settings/
|
||||
.classpath
|
||||
|
||||
# ---> Maven
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
|
||||
|
||||
# --> Idea
|
||||
**/.idea
|
||||
**/*.iml
|
||||
|
||||
# ---> Java
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
# ---> TeX
|
||||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
# *.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.brf
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
|
||||
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
#(e)ledmac/(e)ledpar
|
||||
*.end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
*.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
*.ist
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mtc
|
||||
*.mtc[0-9]
|
||||
*.mtc[1-9][0-9]
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# mylatexformat
|
||||
*.fmt
|
||||
|
||||
# nomencl
|
||||
*.nlo
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# localized versions of JBOSS command line interface
|
||||
*.local.cli
|
||||
|
||||
|
||||
## project specific
|
||||
/source/vvh-access-import/src/main/resources/hibernate.cfg.xml
|
||||
/source/office-parent/office-entities/src/main/resources/META-INF/persistence.xml
|
||||
|
||||
5
_bin/createRelease.bat
Normal file
5
_bin/createRelease.bat
Normal file
@ -0,0 +1,5 @@
|
||||
@ECHO OFF
|
||||
setlocal
|
||||
set BASEPATH=%~dp0%
|
||||
cd %BASEPATH%\..
|
||||
mvn release:clean release:prepare -Dmaven.test.skip=true -Darguments="-Dmaven.test.skip=true -DskipTests"
|
||||
@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.muehlencord.shared</groupId>
|
||||
<artifactId>shared-account</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>ejb</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>shared</artifactId>
|
||||
<groupId>de.muehlencord</groupId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
|
||||
<name>shared-account</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.muehlencord.shared</groupId>
|
||||
<artifactId>shared-jeeutil</artifactId>
|
||||
<type>jar</type>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax</groupId>
|
||||
<artifactId>javaee-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- create EJB version 3.1 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-ejb-plugin</artifactId>
|
||||
<configuration>
|
||||
<ejbVersion>3.1</ejbVersion>
|
||||
<excludes>
|
||||
<exclude>**/persistence.xml</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -1,8 +0,0 @@
|
||||
DROP TABLE config;
|
||||
|
||||
CREATE TABLE config (
|
||||
config_key varchar(100),
|
||||
config_value varchar(200),
|
||||
CONSTRAINT config_pk PRIMARY KEY (config_key)
|
||||
);
|
||||
INSERT INTO config (config_key, config_value) VALUES ('account.maxFailedLogins', '5');
|
||||
@ -1,91 +0,0 @@
|
||||
/**
|
||||
* Author: joern.muehlencord
|
||||
* Created: 06.09.2015
|
||||
*/
|
||||
|
||||
DROP TABLE account_role;
|
||||
DROP TABLE account_history;
|
||||
DROP TABLE account;
|
||||
DROP TABLE role_permission;
|
||||
DROP TABLE application_role;
|
||||
DROP TABLE application_permission;
|
||||
|
||||
|
||||
CREATE TABLE application_role (
|
||||
id UUID NOT NULL,
|
||||
role_name varchar(80) NOT NULL,
|
||||
role_description varchar(200) NOT NULL,
|
||||
CONSTRAINT pk_application_role_pk PRIMARY KEY (id),
|
||||
CONSTRAINT uidx_application_id UNIQUE (id)
|
||||
);
|
||||
|
||||
CREATE TABLE account (
|
||||
id UUID NOT NULL,
|
||||
username varchar(32) NOT NULL,
|
||||
emailaddress varchar(200) NOT NULL,
|
||||
firstname varchar(100) NOT NULL,
|
||||
lastname varchar(100) NOT NULL,
|
||||
account_password char(200) NOT NULL,
|
||||
last_login timestamp with time zone,
|
||||
last_failed_login timestamp with time zone,
|
||||
failure_count int NOT NULL DEFAULT 0,
|
||||
status varchar(10) NOT NULL DEFAULT 'NEW', -- NEW, INIT, OK, BLOCKED,
|
||||
password_reset_ongoing boolean NOT NULL DEFAULT false,
|
||||
password_reset_valid_to timestamp with time zone,
|
||||
password_reset_hash char(200),
|
||||
created_on timestamp with time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
created_by varchar(32) NOT NULL,
|
||||
last_updated_on timestamp with time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
last_updated_by varchar(32) NOT NULL,
|
||||
CONSTRAINT pk_account PRIMARY KEY (id),
|
||||
CONSTRAINT uidx_username UNIQUE (username)
|
||||
);
|
||||
|
||||
CREATE TABLE account_history (
|
||||
id UUID NOT NULL,
|
||||
account_id UUID NOT NULL,
|
||||
message varchar(200),
|
||||
failure_count int NOT NULL DEFAULT 0,
|
||||
status varchar(20) NOT NULL, -- constants needed, after action - new, init, active, blocked, inactive, marked for deletion
|
||||
last_updated_on timestamp with time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
last_updated_by varchar(32) NOT NULL,
|
||||
CONSTRAINT pk_account_history PRIMARY KEY (id),
|
||||
CONSTRAINT fk_account_history_username_fk FOREIGN KEY (account_id) REFERENCES account (id)
|
||||
);
|
||||
|
||||
CREATE TABLE account_role (
|
||||
account UUID NOT NULL,
|
||||
account_role UUID NOT NULL,
|
||||
CONSTRAINT pk_account_role PRIMARY KEY (account, account_role),
|
||||
CONSTRAINT fk_account_role_account FOREIGN KEY (account) REFERENCES account(id),
|
||||
CONSTRAINT fk_account_role_role_name FOREIGN KEY (account_role) REFERENCES application_role(id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE application_permission (
|
||||
id UUID NOT NULL,
|
||||
permission_name varchar(80) NOT NULL,
|
||||
permission_description varchar(200) NOT NULL,
|
||||
CONSTRAINT pk_application_permission PRIMARY KEY (id),
|
||||
CONSTRAINT uidx_application_permission_name UNIQUE (permission_name)
|
||||
);
|
||||
|
||||
CREATE TABLE role_permission (
|
||||
application_role UUID NOT NULL,
|
||||
role_permission UUID NOT NULL,
|
||||
CONSTRAINT pk_role_permission_role_permission_name PRIMARY KEY (application_role, role_permission),
|
||||
CONSTRAINT fk_role_permission_application_role FOREIGN KEY (application_role) REFERENCES application_role(id),
|
||||
CONSTRAINT fk_role_permission_role_permission FOREIGN KEY (role_permission) REFERENCES application_permission(id)
|
||||
);
|
||||
|
||||
INSERT INTO application_permission (id, permission_name, permission_description) values ('dfd0f8f1-4a51-4fdc-9a1c-a942bee9b649', 'test:view', 'Display test view');
|
||||
|
||||
INSERT INTO application_role (id, role_name, role_description) values ('5cd0aca0-5466-483d-8f3e-c369f8061131','Admin', 'Admin role');
|
||||
INSERT INTO application_role (id, role_name, role_description) values ('da30060e-fd23-4016-a506-4e12e9322148', 'User', 'Standard user role');
|
||||
|
||||
-- INSERT INTO role_permission (role_name, permission_name) values ('Admin','test:view');
|
||||
|
||||
INSERT INTO account (id, username, emailaddress, firstname, lastname, account_password, created_by, last_updated_by) values('ab5c8337-6872-4aea-a9b9-78ea63706b8f','admin', 'joern@muehlencord.de', 'Joern', 'Muehlencord','$shiro1$SHA-256$500000$4bHPNH9k539UjdFLgm/HOA==$T/n8skgoGSOtNw/c9ScDlXCiGrx2cZF0Esrvf6WPq6g=', 'admin','admin'); --admin/secret
|
||||
INSERT INTO account_role (account, account_role) values ('ab5c8337-6872-4aea-a9b9-78ea63706b8f', '5cd0aca0-5466-483d-8f3e-c369f8061131');
|
||||
|
||||
--select uuid_generate_v4();
|
||||
@ -1,21 +0,0 @@
|
||||
DROP TABLE mail_template;
|
||||
|
||||
CREATE TABLE mail_template (
|
||||
template_name varchar(40) NOT NULL,
|
||||
template_value text NOT NULL,
|
||||
CONSTRAINT mail_template_pk PRIMARY KEY (template_name)
|
||||
);
|
||||
|
||||
|
||||
INSERT INTO mail_template (template_name, template_value) VALUES('password_reset_html',
|
||||
'<#ftl strip_whitespace = true>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
Dear ${account.firstname},<br>
|
||||
<br>
|
||||
you requested to reset your password at ${parameter.url}. Please open the following URL to proceed.<br>
|
||||
<a href="${parameter.resetUrl}">${parameter.resetUrl}</a><br>
|
||||
<br>
|
||||
</body>
|
||||
</html>');
|
||||
@ -1,2 +0,0 @@
|
||||
\i 01_accounts.sql
|
||||
\i 02_templates.sql
|
||||
@ -1,54 +0,0 @@
|
||||
package de.muehlencord.shared.account.business;
|
||||
|
||||
import de.muehlencord.shared.account.entity.ConfigEntity;
|
||||
import java.io.Serializable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.ejb.Singleton;
|
||||
import javax.ejb.Startup;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Singleton
|
||||
@Startup
|
||||
public class ConfigService implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3195224653632853003L;
|
||||
|
||||
@Inject
|
||||
EntityManager em;
|
||||
|
||||
private String storagePath = null;
|
||||
private int maxFailedLogins = 5;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
ConfigEntity configEntity = em.find(ConfigEntity.class, "storage.path");
|
||||
if (configEntity != null) {
|
||||
this.storagePath = configEntity.getConfigValue();
|
||||
}
|
||||
configEntity = em.find(ConfigEntity.class, "account.maxFailedLogins");
|
||||
if (configEntity != null) {
|
||||
this.maxFailedLogins = Integer.parseInt(configEntity.getConfigValue());
|
||||
}
|
||||
}
|
||||
|
||||
public String getConfigValue(String configKey) {
|
||||
ConfigEntity configEntity = em.find(ConfigEntity.class, configKey);
|
||||
return (configEntity == null ? null : configEntity.getConfigValue());
|
||||
}
|
||||
|
||||
/* *** getter *** */
|
||||
// FIXME remove, this is application specific
|
||||
public String getStoragePath() {
|
||||
return storagePath;
|
||||
}
|
||||
|
||||
public int getMaxFailedLogins() {
|
||||
return maxFailedLogins;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,276 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.account;
|
||||
|
||||
import de.muehlencord.shared.account.business.ConfigService;
|
||||
import de.muehlencord.shared.account.business.mail.MailException;
|
||||
import de.muehlencord.shared.account.business.mail.MailService;
|
||||
import de.muehlencord.shared.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.account.entity.ApplicationRoleEntity;
|
||||
import de.muehlencord.shared.account.util.SecurityUtil;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.ejb.EJB;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.Query;
|
||||
import javax.transaction.Transactional;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Stateless
|
||||
public class AccountControl implements Serializable {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AccountControl.class.getName());
|
||||
private static final long serialVersionUID = 3424816272598108101L;
|
||||
|
||||
@EJB
|
||||
private ConfigService configService;
|
||||
|
||||
@EJB
|
||||
private MailService mailService;
|
||||
|
||||
@Inject
|
||||
EntityManager em;
|
||||
|
||||
public List<AccountEntity> getAccounts() {
|
||||
Query query = em.createQuery("SELECT a FROM AccountEntity a WHERE a.status <> :status", AccountEntity.class);
|
||||
query.setParameter("status", AccountStatus.DISABLED.name());
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
public AccountEntity getAccountEntity(String userName, boolean loadRoles) {
|
||||
StringBuilder queryBuilder = new StringBuilder();
|
||||
queryBuilder.append("SELECT a FROM AccountEntity a ");
|
||||
if (loadRoles) {
|
||||
queryBuilder.append("JOIN FETCH a.applicationRoleList ");
|
||||
}
|
||||
queryBuilder.append("WHERE a.username = :username");
|
||||
Query query = em.createQuery(queryBuilder.toString());
|
||||
query.setParameter("username", userName);
|
||||
try {
|
||||
return (AccountEntity) query.getSingleResult();
|
||||
} catch (NoResultException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
// TODO add role names from application because only application can know how its roles are named
|
||||
public AccountEntity saveAccount(AccountEntity account, boolean isAdmin) {
|
||||
Date now = new Date(); // Todo now in UTC
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
String currentLoggedInUser = currentUser.getPrincipal().toString();
|
||||
|
||||
account.setLastUpdatedBy(currentLoggedInUser);
|
||||
account.setLastUpdatedOn(now);
|
||||
|
||||
boolean newAccount = (account.getCreatedOn() == null);
|
||||
|
||||
// new account
|
||||
if (newAccount) {
|
||||
account.setCreatedOn(now);
|
||||
account.setCreatedBy(currentLoggedInUser);
|
||||
|
||||
// set default random password, user has to get password via lost passwort option afterwards
|
||||
String randomPassword = RandomStringUtils.random(20, true, true);
|
||||
String hashedPassword = SecurityUtil.createPassword(randomPassword);
|
||||
account.setAccountPassword(hashedPassword);
|
||||
em.persist(account);
|
||||
} else {
|
||||
em.merge(account);
|
||||
|
||||
// reload account from db and join roles
|
||||
account = getAccountEntity(account.getUsername(), true);
|
||||
}
|
||||
|
||||
// load Admin or User role from database
|
||||
String roleName = (isAdmin ? "Admin" : "User");
|
||||
Query roleQuery = em.createNamedQuery("ApplicationRoleEntity.findByRoleName");
|
||||
roleQuery.setParameter("roleName", roleName);
|
||||
ApplicationRoleEntity role = (ApplicationRoleEntity) roleQuery.getSingleResult();
|
||||
|
||||
if (role != null) {
|
||||
// add new user add required role
|
||||
// do not request based on newUser variable; this way existing users with missing role (for whatever reason)
|
||||
// will be fixed automatically
|
||||
if (account.getApplicationRoleList() == null || account.getApplicationRoleList().isEmpty()) {
|
||||
account.setApplicationRoleList(new ArrayList<>());
|
||||
account.getApplicationRoleList().add(role);
|
||||
em.merge(account);
|
||||
LOGGER.info("Added role " + roleName + " to user " + account.getUsername());
|
||||
|
||||
} else if (!account.getApplicationRoleList().get(0).equals(role)) {
|
||||
// change role from User to Admin and vice versa
|
||||
// user already exists, has existing role
|
||||
// check if existing role is different from current role and change it
|
||||
// be carefull: this only works as long as a user has exactly one role!
|
||||
// he is either User or Admin
|
||||
// TODO add "UserRole" to every user, make this default Role configurable
|
||||
// TODO add AdminRole in addtion if needed
|
||||
account.getApplicationRoleList().remove(0);
|
||||
account.getApplicationRoleList().add(role);
|
||||
em.merge(account);
|
||||
LOGGER.info("Switched role of user " + account.getUsername() + " to " + roleName);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
public void deleteAccount(AccountEntity account) throws AccountException {
|
||||
Date now = new Date(); // Todo now in UTC
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
String currentUserName = currentUser.getPrincipal().toString();
|
||||
|
||||
if (account.getUsername().equals(currentUserName)) {
|
||||
throw new AccountException("Cannot delete own account");
|
||||
} else {
|
||||
account.setStatus(AccountStatus.DISABLED.name());
|
||||
account.setLastUpdatedBy(currentUserName);
|
||||
account.setLastUpdatedOn(now);
|
||||
em.merge(account);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean initPasswordReset(String userName) {
|
||||
try {
|
||||
AccountEntity account = getAccountEntity(userName, false);
|
||||
if (account == null) {
|
||||
LOGGER.warn("Account with name " + userName + " not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (account.getStatus().equals(AccountStatus.BLOCKED.name())) {
|
||||
LOGGER.warn("Account " + userName + " is locked, cannot initialize password reset");
|
||||
return false;
|
||||
}
|
||||
|
||||
String randomString = RandomStringUtils.random(40, true, true);
|
||||
|
||||
Date validTo = new Date(); // TODO now in UTC
|
||||
validTo = new Date(validTo.getTime() + 1000 * 600); // 10 minutes to react
|
||||
|
||||
account.setPasswordResetHash(randomString);
|
||||
account.setPasswordResetOngoing(true);
|
||||
account.setPasswordResetValidTo(validTo);
|
||||
|
||||
mailService.sendPasswortResetStartEmail(account, randomString);
|
||||
|
||||
em.merge(account);
|
||||
return true;
|
||||
} catch (MailException ex) {
|
||||
LOGGER.error("Error while sending password reset mail. " + ex.toString());
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Error while sending password reset mail.", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean resetPassword(String userName, String newPassword, String resetPasswordToken) {
|
||||
AccountEntity account = getAccountEntity(userName, false);
|
||||
|
||||
if (account == null) {
|
||||
LOGGER.warn("Error while resetting password, no account with username " + userName + " found");
|
||||
// TODO add extra logging for intrusion protection system like fail2ban
|
||||
return false;
|
||||
}
|
||||
|
||||
if (account.getPasswordResetOngoing() && (account.getPasswordResetHash() != null) && (account.getPasswordResetValidTo() != null)) {
|
||||
Date now = new Date(); // TODO now in UTC
|
||||
String storedHash = account.getPasswordResetHash().trim();
|
||||
if (account.getPasswordResetValidTo().after(now)) {
|
||||
if (storedHash.equals(resetPasswordToken)) {
|
||||
// everything ok, reset password
|
||||
executePasswordReset(account, newPassword);
|
||||
LOGGER.info("Updated password for user " + userName);
|
||||
return true;
|
||||
} else {
|
||||
// token is not valid, refuse to change password
|
||||
LOGGER.warn("Trying to reset password for user " + userName + " but wrong token " + resetPasswordToken + " provided");
|
||||
addLoginError(account);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// password reset token no longer valid
|
||||
LOGGER.warn("Trying to reset password for user " + userName + " but token is no longer valid");
|
||||
addLoginError(account);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// user is not is password reset mode
|
||||
LOGGER.warn("Trying to reset password for user " + userName + " but password reset was not requested");
|
||||
addLoginError(account);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void executePasswordReset(AccountEntity account, String newPassword) {
|
||||
Date now = new Date(); // TODO now in UTC
|
||||
|
||||
String hashedPassword = SecurityUtil.createPassword(newPassword);
|
||||
account.setAccountPassword(hashedPassword);
|
||||
|
||||
account.setPasswordResetOngoing(false);
|
||||
account.setPasswordResetHash(null);
|
||||
account.setPasswordResetValidTo(null);
|
||||
|
||||
account.setLastUpdatedBy(account.getUsername());
|
||||
account.setLastUpdatedOn(now);
|
||||
em.merge(account);
|
||||
|
||||
}
|
||||
|
||||
public void updateLogin(AccountEntity account) {
|
||||
Date now = new Date(); // TODO now in UTC
|
||||
// a scucessful login ends a password reset procedure
|
||||
if (account.getPasswordResetOngoing()) {
|
||||
account.setPasswordResetOngoing(false);
|
||||
account.setPasswordResetHash(null);
|
||||
account.setPasswordResetValidTo(null);
|
||||
account.setLastUpdatedOn(now);
|
||||
account.setLastUpdatedBy(account.getUsername());
|
||||
}
|
||||
|
||||
account.setLastLogin(now);
|
||||
account.setFailureCount(0);
|
||||
account.setStatus(AccountStatus.NORMAL.name());
|
||||
|
||||
em.merge(account);
|
||||
}
|
||||
|
||||
public void addLoginError(AccountEntity account) {
|
||||
Date now = new Date(); // TODO now in UTC
|
||||
account.setLastFailedLogin(now);
|
||||
account.setFailureCount(account.getFailureCount() + 1);
|
||||
|
||||
int maxFailedLogins = configService.getMaxFailedLogins();
|
||||
if ((account.getFailureCount() >= maxFailedLogins) && (!account.getStatus().equals("LOCKED"))) { // TOD add status enum
|
||||
// max failed logins reached, disabling user
|
||||
LOGGER.info("Locking account " + account.getUsername() + " due to " + account.getFailureCount() + " failed logins");
|
||||
account.setStatus(AccountStatus.BLOCKED.name());
|
||||
}
|
||||
|
||||
// on a failed login request, disable password reset
|
||||
account.setPasswordResetOngoing(false);
|
||||
account.setPasswordResetHash(null);
|
||||
account.setPasswordResetValidTo(null);
|
||||
|
||||
account.setLastUpdatedBy("system");
|
||||
account.setLastUpdatedOn(now);
|
||||
em.merge(account);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.account;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Raimund
|
||||
*/
|
||||
public class AccountException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new instance of <code>AccountException</code> without detail
|
||||
* message.
|
||||
*/
|
||||
public AccountException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of <code>AccountException</code> with the
|
||||
* specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public AccountException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
AccountException(String entity_updated__deleted_please_reload, boolean b) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.account;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
public enum AccountStatus {
|
||||
|
||||
NEW, // account is created but never used
|
||||
NORMAL, // normal account, at least on login, neither blocked or disabled
|
||||
BLOCKED, // account is blocked after too many login failures or other security related events
|
||||
DISABLED; // account is disabled and cannot be used anymore
|
||||
|
||||
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.account;
|
||||
|
||||
import de.muehlencord.shared.account.entity.ApplicationPermissionEntity;
|
||||
import java.io.Serializable;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.Query;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
@Stateless
|
||||
public class ApplicationPermissionControl implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3761100587901739481L;
|
||||
|
||||
@PersistenceContext
|
||||
EntityManager em;
|
||||
|
||||
public List getApplicationPermissions() {
|
||||
List<ApplicationPermissionEntity> permissionList = em.createNamedQuery("ApplicationPermissionEntity.findAll").getResultList();
|
||||
if (permissionList == null) {
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
return permissionList;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void createOrUpdate(String name, String description) {
|
||||
ApplicationPermissionEntity permission = findByName(name);
|
||||
if (permission == null) {
|
||||
permission = new ApplicationPermissionEntity(name, description);
|
||||
em.persist(permission);
|
||||
} else {
|
||||
permission.setPermissionDescription(description);
|
||||
em.merge(permission);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(ApplicationPermissionEntity permission) throws AccountException {
|
||||
ApplicationPermissionEntity existingPermission = attach(permission);
|
||||
em.remove(existingPermission);
|
||||
}
|
||||
|
||||
public ApplicationPermissionEntity attach(ApplicationPermissionEntity permission) throws AccountException {
|
||||
try {
|
||||
return em.merge(permission);
|
||||
} catch (OptimisticLockException ex) {
|
||||
throw new AccountException("Entity updated / deleted, please reload", true);
|
||||
}
|
||||
}
|
||||
|
||||
private ApplicationPermissionEntity findByName(String name) {
|
||||
Query query = em.createNamedQuery("ApplicationPermissionEntity.findByPermissionName");
|
||||
query.setParameter("permissionName", name);
|
||||
List<ApplicationPermissionEntity> permissions = query.getResultList();
|
||||
if ((permissions == null) || (permissions.isEmpty())) {
|
||||
return null;
|
||||
} else {
|
||||
return permissions.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package de.muehlencord.shared.account.business.account;
|
||||
|
||||
import de.muehlencord.shared.account.entity.ApplicationPermissionEntity;
|
||||
import de.muehlencord.shared.account.entity.ApplicationRoleEntity;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.ejb.EJB;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.Query;
|
||||
import javax.transaction.Transactional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
@Stateless
|
||||
public class ApplicationRoleControl implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5962478269550134748L;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationRoleControl.class);
|
||||
|
||||
@EJB
|
||||
ApplicationPermissionControl applicationPermissionControl;
|
||||
|
||||
@PersistenceContext
|
||||
EntityManager em;
|
||||
|
||||
public List<ApplicationRoleEntity> getAllRoles() {
|
||||
Query query = em.createNamedQuery("ApplicationRoleEntity.findAll");
|
||||
|
||||
List<ApplicationRoleEntity> roles = query.getResultList();
|
||||
if (roles == null) {
|
||||
return new ArrayList<>();
|
||||
} else {
|
||||
return roles;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void createOrUpdate(String name, String description) {
|
||||
ApplicationRoleEntity role = findByName(name);
|
||||
if (role == null) {
|
||||
role = new ApplicationRoleEntity(name, description);
|
||||
em.persist(role);
|
||||
} else {
|
||||
role.setRoleDescription(description);
|
||||
em.merge(role);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(ApplicationRoleEntity permission) throws AccountException {
|
||||
ApplicationRoleEntity existingPermission = attach(permission);
|
||||
em.remove(existingPermission);
|
||||
}
|
||||
|
||||
public ApplicationRoleEntity attach(ApplicationRoleEntity permission) throws AccountException {
|
||||
try {
|
||||
return em.merge(permission);
|
||||
} catch (OptimisticLockException ex) {
|
||||
throw new AccountException("Entity updated / deleted, please reload", true);
|
||||
}
|
||||
}
|
||||
|
||||
private ApplicationRoleEntity findByName(String name) {
|
||||
Query query = em.createNamedQuery("ApplicationRoleEntity.findByRoleName");
|
||||
query.setParameter("roleName", name);
|
||||
List<ApplicationRoleEntity> permissions = query.getResultList();
|
||||
if ((permissions == null) || (permissions.isEmpty())) {
|
||||
return null;
|
||||
} else {
|
||||
return permissions.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ApplicationPermissionEntity> getRolePermissions(ApplicationRoleEntity role) throws AccountException {
|
||||
ApplicationRoleEntity existingRole = em.find(ApplicationRoleEntity.class, role.getId());
|
||||
List<ApplicationPermissionEntity> permissions = existingRole.getApplicationPermissionList();
|
||||
permissions.size(); // force list to load
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public List<ApplicationPermissionEntity> getNotAssignedApplicationPermissions(ApplicationRoleEntity role) {
|
||||
try {
|
||||
List<ApplicationPermissionEntity> rolePermissions = getRolePermissions(role);
|
||||
List<ApplicationPermissionEntity> allPermssions = applicationPermissionControl.getApplicationPermissions();
|
||||
|
||||
List<ApplicationPermissionEntity> missingPermissions = new ArrayList<>();
|
||||
allPermssions.stream().filter((perm) -> (!rolePermissions.contains(perm))).forEachOrdered((perm) -> {
|
||||
missingPermissions.add(perm);
|
||||
});
|
||||
return missingPermissions;
|
||||
} catch (AccountException ex) {
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(ex.toString(), ex);
|
||||
} else {
|
||||
LOGGER.debug(ex.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void addPermission(ApplicationRoleEntity role, ApplicationPermissionEntity permission) throws AccountException {
|
||||
ApplicationRoleEntity existingRole = attach(role);
|
||||
if (existingRole.getApplicationPermissionList() == null) {
|
||||
existingRole.setApplicationPermissionList(new ArrayList<>());
|
||||
}
|
||||
existingRole.getApplicationPermissionList().add(permission);
|
||||
em.merge(role);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void removePermission(ApplicationRoleEntity role, ApplicationPermissionEntity permission) throws AccountException {
|
||||
ApplicationRoleEntity existingRole = attach(role);
|
||||
if ((existingRole.getApplicationPermissionList() != null) && (existingRole.getApplicationPermissionList().contains(permission))) {
|
||||
existingRole.getApplicationPermissionList().remove(permission);
|
||||
}
|
||||
em.merge(role);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.mail;
|
||||
|
||||
import de.muehlencord.shared.account.entity.AccountEntity;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
*/
|
||||
public class MailDatamodel {
|
||||
|
||||
private final AccountEntity account;
|
||||
private final Map<String,Object> parameter;
|
||||
|
||||
public MailDatamodel() {
|
||||
this.account = null;
|
||||
this.parameter = new HashMap<>();
|
||||
}
|
||||
|
||||
public MailDatamodel(AccountEntity account) {
|
||||
this.parameter = new HashMap<>();
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public void addParameter(String name, Object value) {
|
||||
this.parameter.put(name, value);
|
||||
}
|
||||
|
||||
|
||||
/* **** getter / setter **** */
|
||||
|
||||
public AccountEntity getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public Map<String, Object> getParameter() {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.mail;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Raimund
|
||||
*/
|
||||
public class MailException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new instance of <code>MailException</code> without detail
|
||||
* message.
|
||||
*/
|
||||
public MailException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of <code>MailException</code> with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public MailException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of <code>MailException</code> with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param th the root cause
|
||||
*/
|
||||
public MailException(String msg, Throwable th) {
|
||||
super(msg, th);
|
||||
}
|
||||
}
|
||||
@ -1,192 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.mail;
|
||||
|
||||
import de.muehlencord.shared.account.configuration.AccountConfigurationKey;
|
||||
import de.muehlencord.shared.account.entity.AccountEntity;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Resource;
|
||||
import javax.ejb.EJB;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeBodyPart;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import de.muehlencord.shared.account.configuration.AccountConfigurationValue;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Stateless
|
||||
public class MailService implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1937218474908356747L;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MailService.class);
|
||||
|
||||
@EJB
|
||||
private MailTemplateService mailTemplateService;
|
||||
|
||||
@Inject
|
||||
@AccountConfigurationValue(key = AccountConfigurationKey.BaseUrl)
|
||||
private String baseUrl;
|
||||
|
||||
@Inject
|
||||
@AccountConfigurationValue(key = AccountConfigurationKey.PasswordResetUrl)
|
||||
private String passwordResetUrl;
|
||||
|
||||
// TODO make this configurable by injection from the application it uses it, fall back to defaul mail setup if not available
|
||||
@Resource(lookup = "java:jboss/mail/ssgMail")
|
||||
private Session mailSession;
|
||||
|
||||
public String sendTestEmail(String recipient) throws MailException {
|
||||
return sendMail(recipient, "Test email", "This is a test email");
|
||||
}
|
||||
|
||||
public String sendTestHtmlEmail(String recipient) throws MailException {
|
||||
Date now = new Date();
|
||||
AccountEntity account = new AccountEntity(UUID.randomUUID(), "joern.muehlencord", "joern@muehlencord.de", "Jörn", "Mühlencord", "secret", 0, "NEW", false, now, "admin", now, "admin");
|
||||
MailDatamodel dataModel = new MailDatamodel(account);
|
||||
dataModel.addParameter("url", "http://url.de");
|
||||
dataModel.addParameter("resetUrl", "http://reseturl.de");
|
||||
return sendHTMLMail(recipient, "Test HTML Email", dataModel, "password_reset_html");
|
||||
}
|
||||
|
||||
public String sendMail(String recipient, String subject, String body) throws MailException {
|
||||
try {
|
||||
MimeMessage message = new MimeMessage(mailSession);
|
||||
message.setSubject(subject, "UTF-8");
|
||||
message.setFrom();
|
||||
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient, false));
|
||||
message.setText(body, "UTF-8");
|
||||
return transportMail(message);
|
||||
} catch (MessagingException ex) {
|
||||
throw new MailException("Error while sending email.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String sendHTMLMail(String recipient, String subject, MailDatamodel dataModel, String templateName) throws MailException {
|
||||
return sendHTMLMail(recipient, subject, dataModel, templateName, null);
|
||||
}
|
||||
|
||||
public String sendHTMLMail(String recipient, String subject, MailDatamodel dataModel, String htmlTemplateName, String plainTemplateName) throws MailException {
|
||||
return sendHTMLMail(recipient, null, null, subject, dataModel, htmlTemplateName, plainTemplateName, "UTF-8", new ArrayList<>());
|
||||
}
|
||||
|
||||
public String sendHTMLMail(String recipient, String ccRecipient, String bccRecipient, String subject, MailDatamodel dataModel, String htmlTemplateName, String plainTemplateName) throws MailException {
|
||||
return sendHTMLMail(recipient, ccRecipient, bccRecipient, subject, dataModel, htmlTemplateName, plainTemplateName, "UTF-8", new ArrayList<>());
|
||||
}
|
||||
|
||||
public String sendHTMLMail(String recipient, String ccRecipient, String bccRecipient, String subject,
|
||||
MailDatamodel dataModel, String htmlTemplateName, String plainTemplateName, String encoding, List<File> attachments) throws MailException {
|
||||
try {
|
||||
MimeMessage message = new MimeMessage(mailSession);
|
||||
message.setFrom(); // use default from
|
||||
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient, false));
|
||||
if (ccRecipient != null) {
|
||||
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccRecipient, false));
|
||||
}
|
||||
if (bccRecipient != null) {
|
||||
message.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(bccRecipient, false));
|
||||
}
|
||||
|
||||
message.setSubject(subject, encoding);
|
||||
|
||||
Multipart contentMultiPart = new MimeMultipart("alternative");
|
||||
|
||||
String htmlBody = mailTemplateService.getStringFromTemplate(htmlTemplateName, dataModel);
|
||||
MimeBodyPart htmlBodyPart = new MimeBodyPart();
|
||||
htmlBodyPart.setContent(htmlBody, "text/html; charset=UTF-8");
|
||||
contentMultiPart.addBodyPart(htmlBodyPart);
|
||||
|
||||
if (plainTemplateName != null) {
|
||||
String plainBody = mailTemplateService.getStringFromTemplate(plainTemplateName, dataModel);
|
||||
MimeBodyPart plainBodyPart = new MimeBodyPart();
|
||||
plainBodyPart.setText(plainBody, "UTF-8");
|
||||
contentMultiPart.addBodyPart(plainBodyPart);
|
||||
}
|
||||
|
||||
|
||||
if ((attachments == null) || (attachments.isEmpty())) {
|
||||
message.setContent(contentMultiPart);
|
||||
} else {
|
||||
MimeBodyPart contentBodyPart = new MimeBodyPart();
|
||||
contentBodyPart.setContent(contentMultiPart);
|
||||
|
||||
MimeMultipart messageMultipart = new MimeMultipart("related");
|
||||
messageMultipart.addBodyPart(contentBodyPart);
|
||||
for (File attachment : attachments) {
|
||||
try {
|
||||
MimeBodyPart attachmentBodyPart = new MimeBodyPart();
|
||||
attachmentBodyPart.attachFile(attachment);
|
||||
String contentType = Files.probeContentType(attachment.toPath());
|
||||
if (contentType != null) {
|
||||
attachmentBodyPart.setHeader("Content-Type", contentType);
|
||||
}
|
||||
messageMultipart.addBodyPart(attachmentBodyPart);
|
||||
} catch (IOException ex) {
|
||||
throw new MailException("Cannot attach " + attachment.toString() + " to email. Reason: " + ex.toString(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
message.setContent (messageMultipart);
|
||||
}
|
||||
|
||||
return transportMail(message);
|
||||
} catch (MessagingException | MailTemplateException ex) {
|
||||
throw new MailException("Error while sending email.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String sendPasswortResetStartEmail(AccountEntity account, String token) throws MailException {
|
||||
MailDatamodel model = new MailDatamodel(account);
|
||||
|
||||
/* old aproach via FacesContext - add this back as fallback if injection point if not configured
|
||||
try {
|
||||
// String absoluteWebPath = FacesContext.getCurrentInstance().getExternalContext().getApplicationContextPath();
|
||||
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
|
||||
String resetPage = "/login.xhtml?token=" + token;
|
||||
URL baseUrl;
|
||||
|
||||
// TODO move out of this class, this is not mandatorily connected to a form
|
||||
baseUrl = new URL(externalContext.getRequestScheme(),
|
||||
externalContext.getRequestServerName(),
|
||||
externalContext.getRequestServerPort(),
|
||||
externalContext.getRequestContextPath());
|
||||
model.addParameter("url", baseUrl.toString());
|
||||
model.addParameter("resetUrl", baseUrl.toString() + resetPage);
|
||||
} catch (MalformedURLException ex) {
|
||||
throw new MailException("Error while sending email.", ex);
|
||||
}
|
||||
String baseUrl = configService.getConfigValue(configKey);
|
||||
String resetUrlWithToken = baseUrl + "/login.xhtml?token=" + token;
|
||||
*/
|
||||
String resetUrlWithToken = passwordResetUrl + "?token=" + token;
|
||||
model.addParameter("url", baseUrl);
|
||||
model.addParameter("resetUrl", resetUrlWithToken);
|
||||
return sendHTMLMail(account.getEmailaddress(), "Reset your password", model, "password_reset_html");
|
||||
}
|
||||
|
||||
private String transportMail(Message message) throws MessagingException {
|
||||
message.setSentDate(new Date());
|
||||
Transport.send(message);
|
||||
String messageId = message.getHeader("Message-ID")[0];
|
||||
LOGGER.info("Mail sent to {}, messageid = {}", message.getAllRecipients()[0].toString(), messageId);
|
||||
return messageId;
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.mail;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
*/
|
||||
public class MailTemplateException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new instance of <code>MailTemplateException</code> without
|
||||
* detail message.
|
||||
*/
|
||||
public MailTemplateException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of <code>MailTemplateException</code> with the
|
||||
* specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public MailTemplateException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of <code>MailTemplateException</code> with the
|
||||
* specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param th the root cause
|
||||
*/
|
||||
public MailTemplateException(String msg, Throwable th) {
|
||||
super(msg, th);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,67 +0,0 @@
|
||||
package de.muehlencord.shared.account.business.mail;
|
||||
|
||||
import de.muehlencord.shared.account.entity.MailTemplateEntity;
|
||||
import freemarker.cache.StringTemplateLoader;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateExceptionHandler;
|
||||
import java.io.Serializable;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import javax.ejb.Stateless;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
*/
|
||||
@Stateless
|
||||
public class MailTemplateService implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -136113381443058697L;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MailTemplateService.class.getName());
|
||||
|
||||
@Inject
|
||||
EntityManager em;
|
||||
|
||||
public String getStringFromTemplate(String templateName, MailDatamodel dataModel) throws MailTemplateException {
|
||||
try {
|
||||
Query query = em.createNamedQuery("MailTemplateEntity.findByTemplateName");
|
||||
query.setParameter("templateName", templateName);
|
||||
MailTemplateEntity templateEntity = (MailTemplateEntity) query.getSingleResult();
|
||||
if (templateEntity == null) {
|
||||
LOGGER.error("Tempate with name " + templateName + " not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
|
||||
configuration.setDefaultEncoding("UTF-8"); // FIXME make encoding configurable
|
||||
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||
|
||||
StringTemplateLoader stringLoader = new StringTemplateLoader();
|
||||
stringLoader.putTemplate(templateEntity.getTemplateName(), templateEntity.getTemplateValue());
|
||||
configuration.setTemplateLoader(stringLoader);
|
||||
|
||||
Template template = configuration.getTemplate(templateEntity.getTemplateName());
|
||||
|
||||
Writer out = new StringWriter();
|
||||
template.process(dataModel, out);
|
||||
String templateString = out.toString();
|
||||
return templateString;
|
||||
} catch (Exception ex) {
|
||||
String hint = "Error while processing template with name " + templateName + ".";
|
||||
LOGGER.error(hint + " " + ex.toString());
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(hint, ex);
|
||||
}
|
||||
throw new MailTemplateException(hint, ex);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package de.muehlencord.shared.account.configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
public enum AccountConfigurationKey {
|
||||
// the base path of the application
|
||||
BaseUrl,
|
||||
// the full pass to the reset password page
|
||||
PasswordResetUrl,
|
||||
// injection handler
|
||||
Producer;
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package de.muehlencord.shared.account.configuration;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.enterprise.util.Nonbinding;
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Qualifier
|
||||
public @interface AccountConfigurationValue {
|
||||
|
||||
@Nonbinding
|
||||
AccountConfigurationKey key();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package de.muehlencord.shared.account.entity;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
public interface Account {
|
||||
|
||||
String getUsername();
|
||||
|
||||
}
|
||||
@ -1,348 +0,0 @@
|
||||
package de.muehlencord.shared.account.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "account")
|
||||
@XmlRootElement
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "AccountEntity.findAll", query = "SELECT a FROM AccountEntity a"),
|
||||
@NamedQuery(name = "AccountEntity.findByUsername", query = "SELECT a FROM AccountEntity a WHERE a.username = :username"),
|
||||
@NamedQuery(name = "AccountEntity.findByEmailaddress", query = "SELECT a FROM AccountEntity a WHERE a.emailaddress = :emailaddress"),
|
||||
@NamedQuery(name = "AccountEntity.findByFirstname", query = "SELECT a FROM AccountEntity a WHERE a.firstname = :firstname"),
|
||||
@NamedQuery(name = "AccountEntity.findByLastname", query = "SELECT a FROM AccountEntity a WHERE a.lastname = :lastname"),
|
||||
@NamedQuery(name = "AccountEntity.findByAccountPassword", query = "SELECT a FROM AccountEntity a WHERE a.accountPassword = :accountPassword"),
|
||||
@NamedQuery(name = "AccountEntity.findByLastLogin", query = "SELECT a FROM AccountEntity a WHERE a.lastLogin = :lastLogin"),
|
||||
@NamedQuery(name = "AccountEntity.findByLastFailedLogin", query = "SELECT a FROM AccountEntity a WHERE a.lastFailedLogin = :lastFailedLogin"),
|
||||
@NamedQuery(name = "AccountEntity.findByFailureCount", query = "SELECT a FROM AccountEntity a WHERE a.failureCount = :failureCount"),
|
||||
@NamedQuery(name = "AccountEntity.findByStatus", query = "SELECT a FROM AccountEntity a WHERE a.status = :status"),
|
||||
@NamedQuery(name = "AccountEntity.findByPasswordResetOngoing", query = "SELECT a FROM AccountEntity a WHERE a.passwordResetOngoing = :passwordResetOngoing"),
|
||||
@NamedQuery(name = "AccountEntity.findByPasswordResetValidTo", query = "SELECT a FROM AccountEntity a WHERE a.passwordResetValidTo = :passwordResetValidTo"),
|
||||
@NamedQuery(name = "AccountEntity.findByPasswordResetHash", query = "SELECT a FROM AccountEntity a WHERE a.passwordResetHash = :passwordResetHash"),
|
||||
@NamedQuery(name = "AccountEntity.findByCreatedOn", query = "SELECT a FROM AccountEntity a WHERE a.createdOn = :createdOn"),
|
||||
@NamedQuery(name = "AccountEntity.findByCreatedBy", query = "SELECT a FROM AccountEntity a WHERE a.createdBy = :createdBy"),
|
||||
@NamedQuery(name = "AccountEntity.findByLastUpdatedOn", query = "SELECT a FROM AccountEntity a WHERE a.lastUpdatedOn = :lastUpdatedOn"),
|
||||
@NamedQuery(name = "AccountEntity.findByLastUpdatedBy", query = "SELECT a FROM AccountEntity a WHERE a.lastUpdatedBy = :lastUpdatedBy")})
|
||||
public class AccountEntity implements Serializable, Account {
|
||||
|
||||
private static final long serialVersionUID = 6216991757526150935L;
|
||||
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Type(type = "pg-uuid")
|
||||
private UUID id;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 32)
|
||||
@Column(name = "username")
|
||||
private String username;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 200)
|
||||
@Column(name = "emailaddress")
|
||||
private String emailaddress;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
@Column(name = "firstname")
|
||||
private String firstname;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
@Column(name = "lastname")
|
||||
private String lastname;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 200)
|
||||
@Column(name = "account_password", columnDefinition = "bpchar(200)")
|
||||
private String accountPassword;
|
||||
@Column(name = "last_login")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date lastLogin;
|
||||
@Column(name = "last_failed_login")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date lastFailedLogin;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "failure_count")
|
||||
private int failureCount;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 10)
|
||||
@Column(name = "status")
|
||||
private String status;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "password_reset_ongoing")
|
||||
private boolean passwordResetOngoing;
|
||||
@Column(name = "password_reset_valid_to")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date passwordResetValidTo;
|
||||
@Size(max = 200)
|
||||
@Column(name = "password_reset_hash", columnDefinition = "bpchar(200)")
|
||||
private String passwordResetHash;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "created_on")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date createdOn;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 32)
|
||||
@Column(name = "created_by")
|
||||
private String createdBy;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "last_updated_on")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date lastUpdatedOn;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 32)
|
||||
@Column(name = "last_updated_by")
|
||||
private String lastUpdatedBy;
|
||||
@JoinTable(name = "account_role", joinColumns = {
|
||||
@JoinColumn(name = "account", referencedColumnName = "id")}, inverseJoinColumns = {
|
||||
@JoinColumn(name = "account_role", referencedColumnName = "id")})
|
||||
@ManyToMany(fetch = FetchType.LAZY)
|
||||
private List<ApplicationRoleEntity> applicationRoleList;
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "accountId", fetch = FetchType.LAZY)
|
||||
private List<AccountHistoryEntity> accountHistoryList;
|
||||
|
||||
public AccountEntity() {
|
||||
}
|
||||
|
||||
public AccountEntity(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AccountEntity(UUID id, String username, String emailaddress, String firstname, String lastname, String accountPassword, int failureCount, String status, boolean passwordResetOngoing, Date createdOn, String createdBy, Date lastUpdatedOn, String lastUpdatedBy) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.emailaddress = emailaddress;
|
||||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
this.accountPassword = accountPassword;
|
||||
this.failureCount = failureCount;
|
||||
this.status = status;
|
||||
this.passwordResetOngoing = passwordResetOngoing;
|
||||
this.createdOn = createdOn;
|
||||
this.createdBy = createdBy;
|
||||
this.lastUpdatedOn = lastUpdatedOn;
|
||||
this.lastUpdatedBy = lastUpdatedBy;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmailaddress() {
|
||||
return emailaddress;
|
||||
}
|
||||
|
||||
public void setEmailaddress(String emailaddress) {
|
||||
this.emailaddress = emailaddress;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public String getAccountPassword() {
|
||||
return accountPassword;
|
||||
}
|
||||
|
||||
public void setAccountPassword(String accountPassword) {
|
||||
this.accountPassword = accountPassword;
|
||||
}
|
||||
|
||||
public Date getLastLogin() {
|
||||
return lastLogin;
|
||||
}
|
||||
|
||||
public void setLastLogin(Date lastLogin) {
|
||||
this.lastLogin = lastLogin;
|
||||
}
|
||||
|
||||
public Date getLastFailedLogin() {
|
||||
return lastFailedLogin;
|
||||
}
|
||||
|
||||
public void setLastFailedLogin(Date lastFailedLogin) {
|
||||
this.lastFailedLogin = lastFailedLogin;
|
||||
}
|
||||
|
||||
public int getFailureCount() {
|
||||
return failureCount;
|
||||
}
|
||||
|
||||
public void setFailureCount(int failureCount) {
|
||||
this.failureCount = failureCount;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public boolean getPasswordResetOngoing() {
|
||||
return passwordResetOngoing;
|
||||
}
|
||||
|
||||
public void setPasswordResetOngoing(boolean passwordResetOngoing) {
|
||||
this.passwordResetOngoing = passwordResetOngoing;
|
||||
}
|
||||
|
||||
public Date getPasswordResetValidTo() {
|
||||
return passwordResetValidTo;
|
||||
}
|
||||
|
||||
public void setPasswordResetValidTo(Date passwordResetValidTo) {
|
||||
this.passwordResetValidTo = passwordResetValidTo;
|
||||
}
|
||||
|
||||
public String getPasswordResetHash() {
|
||||
return passwordResetHash;
|
||||
}
|
||||
|
||||
public void setPasswordResetHash(String passwordResetHash) {
|
||||
this.passwordResetHash = passwordResetHash;
|
||||
}
|
||||
|
||||
public Date getCreatedOn() {
|
||||
return createdOn;
|
||||
}
|
||||
|
||||
public void setCreatedOn(Date createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public void setCreatedBy(String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
public Date getLastUpdatedOn() {
|
||||
return lastUpdatedOn;
|
||||
}
|
||||
|
||||
public void setLastUpdatedOn(Date lastUpdatedOn) {
|
||||
this.lastUpdatedOn = lastUpdatedOn;
|
||||
}
|
||||
|
||||
public String getLastUpdatedBy() {
|
||||
return lastUpdatedBy;
|
||||
}
|
||||
|
||||
public void setLastUpdatedBy(String lastUpdatedBy) {
|
||||
this.lastUpdatedBy = lastUpdatedBy;
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public List<ApplicationRoleEntity> getApplicationRoleList() {
|
||||
return applicationRoleList;
|
||||
}
|
||||
|
||||
public void setApplicationRoleList(List<ApplicationRoleEntity> applicationRoleList) {
|
||||
this.applicationRoleList = applicationRoleList;
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public List<AccountHistoryEntity> getAccountHistoryList() {
|
||||
return accountHistoryList;
|
||||
}
|
||||
|
||||
public void setAccountHistoryList(List<AccountHistoryEntity> accountHistoryList) {
|
||||
this.accountHistoryList = accountHistoryList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (id != null ? id.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof AccountEntity)) {
|
||||
return false;
|
||||
}
|
||||
AccountEntity other = (AccountEntity) object;
|
||||
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.shared.account.entity.Account[ id=" + id + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,172 +0,0 @@
|
||||
package de.muehlencord.shared.account.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "account_history")
|
||||
@XmlRootElement
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "AccountHistoryEntity.findAll", query = "SELECT a FROM AccountHistoryEntity a"),
|
||||
@NamedQuery(name = "AccountHistoryEntity.findById", query = "SELECT a FROM AccountHistoryEntity a WHERE a.id = :id"),
|
||||
@NamedQuery(name = "AccountHistoryEntity.findByMessage", query = "SELECT a FROM AccountHistoryEntity a WHERE a.message = :message"),
|
||||
@NamedQuery(name = "AccountHistoryEntity.findByFailureCount", query = "SELECT a FROM AccountHistoryEntity a WHERE a.failureCount = :failureCount"),
|
||||
@NamedQuery(name = "AccountHistoryEntity.findByStatus", query = "SELECT a FROM AccountHistoryEntity a WHERE a.status = :status"),
|
||||
@NamedQuery(name = "AccountHistoryEntity.findByLastUpdatedOn", query = "SELECT a FROM AccountHistoryEntity a WHERE a.lastUpdatedOn = :lastUpdatedOn"),
|
||||
@NamedQuery(name = "AccountHistoryEntity.findByLastUpdatedBy", query = "SELECT a FROM AccountHistoryEntity a WHERE a.lastUpdatedBy = :lastUpdatedBy")})
|
||||
public class AccountHistoryEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Type(type = "pg-uuid")
|
||||
private UUID id;
|
||||
@Size(max = 200)
|
||||
@Column(name = "message")
|
||||
private String message;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "failure_count")
|
||||
private int failureCount;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 20)
|
||||
@Column(name = "status")
|
||||
private String status;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "last_updated_on")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date lastUpdatedOn;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 32)
|
||||
@Column(name = "last_updated_by")
|
||||
private String lastUpdatedBy;
|
||||
@JoinColumn(name = "account_id", referencedColumnName = "id")
|
||||
@ManyToOne(optional = false)
|
||||
private AccountEntity accountId;
|
||||
|
||||
public AccountHistoryEntity() {
|
||||
}
|
||||
|
||||
public AccountHistoryEntity(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AccountHistoryEntity(UUID id, int failureCount, String status, Date lastUpdatedOn, String lastUpdatedBy) {
|
||||
this.id = id;
|
||||
this.failureCount = failureCount;
|
||||
this.status = status;
|
||||
this.lastUpdatedOn = lastUpdatedOn;
|
||||
this.lastUpdatedBy = lastUpdatedBy;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getFailureCount() {
|
||||
return failureCount;
|
||||
}
|
||||
|
||||
public void setFailureCount(int failureCount) {
|
||||
this.failureCount = failureCount;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Date getLastUpdatedOn() {
|
||||
return lastUpdatedOn;
|
||||
}
|
||||
|
||||
public void setLastUpdatedOn(Date lastUpdatedOn) {
|
||||
this.lastUpdatedOn = lastUpdatedOn;
|
||||
}
|
||||
|
||||
public String getLastUpdatedBy() {
|
||||
return lastUpdatedBy;
|
||||
}
|
||||
|
||||
public void setLastUpdatedBy(String lastUpdatedBy) {
|
||||
this.lastUpdatedBy = lastUpdatedBy;
|
||||
}
|
||||
|
||||
public AccountEntity getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(AccountEntity accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (id != null ? id.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof AccountHistoryEntity)) {
|
||||
return false;
|
||||
}
|
||||
AccountHistoryEntity other = (AccountHistoryEntity) object;
|
||||
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.shared.account.entity.AccountHistory[ id=" + id + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,136 +0,0 @@
|
||||
package de.muehlencord.shared.account.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "application_permission")
|
||||
@XmlRootElement
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "ApplicationPermissionEntity.findAll", query = "SELECT a FROM ApplicationPermissionEntity a order by a.permissionName"),
|
||||
@NamedQuery(name = "ApplicationPermissionEntity.findNotAssigned", query = "SELECT a FROM ApplicationPermissionEntity a LEFT OUTER JOIN a.applicationRoleList r WHERE r NOT IN :permissions"),
|
||||
@NamedQuery(name = "ApplicationPermissionEntity.findByPermissionName", query = "SELECT a FROM ApplicationPermissionEntity a WHERE a.permissionName = :permissionName"),
|
||||
@NamedQuery(name = "ApplicationPermissionEntity.findByPermissionDescription", query = "SELECT a FROM ApplicationPermissionEntity a WHERE a.permissionDescription = :permissionDescription")})
|
||||
public class ApplicationPermissionEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8985982754544829534L;
|
||||
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Type(type = "pg-uuid")
|
||||
private UUID id;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 80)
|
||||
@Column(name = "permission_name")
|
||||
private String permissionName;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 200)
|
||||
@Column(name = "permission_description")
|
||||
private String permissionDescription;
|
||||
@ManyToMany(mappedBy = "applicationPermissionList")
|
||||
private List<ApplicationRoleEntity> applicationRoleList;
|
||||
|
||||
public ApplicationPermissionEntity() {
|
||||
}
|
||||
|
||||
public ApplicationPermissionEntity(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ApplicationPermissionEntity(String permissionName, String permissionDescription) {
|
||||
this.id = null;
|
||||
this.permissionName = permissionName;
|
||||
this.permissionDescription = permissionDescription;
|
||||
}
|
||||
|
||||
public ApplicationPermissionEntity(UUID id, String permissionName, String permissionDescription) {
|
||||
this.id = id;
|
||||
this.permissionName = permissionName;
|
||||
this.permissionDescription = permissionDescription;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPermissionName() {
|
||||
return permissionName;
|
||||
}
|
||||
|
||||
public void setPermissionName(String permissionName) {
|
||||
this.permissionName = permissionName;
|
||||
}
|
||||
|
||||
public String getPermissionDescription() {
|
||||
return permissionDescription;
|
||||
}
|
||||
|
||||
public void setPermissionDescription(String permissionDescription) {
|
||||
this.permissionDescription = permissionDescription;
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public List<ApplicationRoleEntity> getApplicationRoleList() {
|
||||
return applicationRoleList;
|
||||
}
|
||||
|
||||
public void setApplicationRoleList(List<ApplicationRoleEntity> applicationRoleList) {
|
||||
this.applicationRoleList = applicationRoleList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (id != null ? id.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof ApplicationPermissionEntity)) {
|
||||
return false;
|
||||
}
|
||||
ApplicationPermissionEntity other = (ApplicationPermissionEntity) object;
|
||||
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.shared.account.entity.ApplicationPermission[ id=" + id + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,152 +0,0 @@
|
||||
package de.muehlencord.shared.account.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Type;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "application_role")
|
||||
@XmlRootElement
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "ApplicationRoleEntity.findAll", query = "SELECT a FROM ApplicationRoleEntity a ORDER BY a.roleName")
|
||||
, @NamedQuery(name = "ApplicationRoleEntity.findByRoleName", query = "SELECT a FROM ApplicationRoleEntity a WHERE a.roleName = :roleName")
|
||||
, @NamedQuery(name = "ApplicationRoleEntity.findByRoleDescription", query = "SELECT a FROM ApplicationRoleEntity a WHERE a.roleDescription = :roleDescription")})
|
||||
|
||||
public class ApplicationRoleEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8324054525780893823L;
|
||||
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Type(type = "pg-uuid")
|
||||
private UUID id;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 80)
|
||||
@Column(name = "role_name")
|
||||
private String roleName;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 200)
|
||||
@Column(name = "role_description")
|
||||
private String roleDescription;
|
||||
@ManyToMany(mappedBy = "applicationRoleList")
|
||||
private List<AccountEntity> accountList;
|
||||
@JoinTable(name = "role_permission", joinColumns = {
|
||||
@JoinColumn(name = "application_role", referencedColumnName = "id")}, inverseJoinColumns = {
|
||||
@JoinColumn(name = "role_permission", referencedColumnName = "id")})
|
||||
@ManyToMany
|
||||
private List<ApplicationPermissionEntity> applicationPermissionList;
|
||||
|
||||
public ApplicationRoleEntity() {
|
||||
}
|
||||
|
||||
public ApplicationRoleEntity(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ApplicationRoleEntity(String roleName, String roleDescription) {
|
||||
this.id = null;
|
||||
this.roleName = roleName;
|
||||
this.roleDescription = roleDescription;
|
||||
}
|
||||
|
||||
public ApplicationRoleEntity(UUID id, String roleName, String roleDescription) {
|
||||
this.id = id;
|
||||
this.roleName = roleName;
|
||||
this.roleDescription = roleDescription;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getRoleName() {
|
||||
return roleName;
|
||||
}
|
||||
|
||||
public void setRoleName(String roleName) {
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public String getRoleDescription() {
|
||||
return roleDescription;
|
||||
}
|
||||
|
||||
public void setRoleDescription(String roleDescription) {
|
||||
this.roleDescription = roleDescription;
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public List<AccountEntity> getAccountList() {
|
||||
return accountList;
|
||||
}
|
||||
|
||||
public void setAccountList(List<AccountEntity> accountList) {
|
||||
this.accountList = accountList;
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public List<ApplicationPermissionEntity> getApplicationPermissionList() {
|
||||
return applicationPermissionList;
|
||||
}
|
||||
|
||||
public void setApplicationPermissionList(List<ApplicationPermissionEntity> applicationPermissionList) {
|
||||
this.applicationPermissionList = applicationPermissionList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (id != null ? id.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof ApplicationRoleEntity)) {
|
||||
return false;
|
||||
}
|
||||
ApplicationRoleEntity other = (ApplicationRoleEntity) object;
|
||||
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.shared.account.entity.ApplicationRole[ id=" + id + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,111 +0,0 @@
|
||||
package de.muehlencord.shared.account.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.QueryHint;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "config")
|
||||
@XmlRootElement
|
||||
@Cacheable(true)
|
||||
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "Configuration")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "ConfigEntity.findAll", query = "SELECT c FROM ConfigEntity c ORDER BY c.configKey",
|
||||
hints = {
|
||||
@QueryHint(name = "org.hibernate.cacheable", value = "true")
|
||||
, @QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})
|
||||
, @NamedQuery(name = "ConfigEntity.findByConfigKey", query = "SELECT c FROM ConfigEntity c WHERE c.configKey = :configKey",
|
||||
hints = {
|
||||
@QueryHint(name = "org.hibernate.cacheable", value = "true")
|
||||
, @QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})
|
||||
|
||||
, @NamedQuery(name = "ConfigEntity.findByConfigValue", query = "SELECT c FROM ConfigEntity c WHERE c.configValue = :configValue",
|
||||
hints = {
|
||||
@QueryHint(name = "org.hibernate.cacheable", value = "true")
|
||||
, @QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})
|
||||
})
|
||||
|
||||
public class ConfigEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2013982316933782223L;
|
||||
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
@Column(name = "config_key")
|
||||
private String configKey;
|
||||
@Size(max = 200)
|
||||
@Column(name = "config_value")
|
||||
private String configValue;
|
||||
|
||||
public ConfigEntity() {
|
||||
}
|
||||
|
||||
public ConfigEntity(String configKey) {
|
||||
this.configKey = configKey;
|
||||
}
|
||||
|
||||
public ConfigEntity(String configKey, String configValue) {
|
||||
this.configKey = configKey;
|
||||
this.configValue = configValue;
|
||||
}
|
||||
|
||||
public String getConfigKey() {
|
||||
return configKey;
|
||||
}
|
||||
|
||||
public void setConfigKey(String configKey) {
|
||||
this.configKey = configKey;
|
||||
}
|
||||
|
||||
public String getConfigValue() {
|
||||
return configValue;
|
||||
}
|
||||
|
||||
public void setConfigValue(String configValue) {
|
||||
this.configValue = configValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (configKey != null ? configKey.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof ConfigEntity)) {
|
||||
return false;
|
||||
}
|
||||
ConfigEntity other = (ConfigEntity) object;
|
||||
if ((this.configKey == null && other.configKey != null) || (this.configKey != null && !this.configKey.equals(other.configKey))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.shared.account.entity.Config[ configKey=" + configKey + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,95 +0,0 @@
|
||||
package de.muehlencord.shared.account.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "mail_template")
|
||||
@XmlRootElement
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "MailTemplateEntity.findAll", query = "SELECT m FROM MailTemplateEntity m"),
|
||||
@NamedQuery(name = "MailTemplateEntity.findByTemplateName", query = "SELECT m FROM MailTemplateEntity m WHERE m.templateName = :templateName"),
|
||||
@NamedQuery(name = "MailTemplateEntity.findByTemplateValue", query = "SELECT m FROM MailTemplateEntity m WHERE m.templateValue = :templateValue")})
|
||||
public class MailTemplateEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4527399247302581555L;
|
||||
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 40)
|
||||
@Column(name = "template_name")
|
||||
private String templateName;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 2147483647)
|
||||
@Column(name = "template_value")
|
||||
private String templateValue;
|
||||
|
||||
public MailTemplateEntity() {
|
||||
}
|
||||
|
||||
public MailTemplateEntity(String templateName) {
|
||||
this.templateName = templateName;
|
||||
}
|
||||
|
||||
public MailTemplateEntity(String templateName, String templateValue) {
|
||||
this.templateName = templateName;
|
||||
this.templateValue = templateValue;
|
||||
}
|
||||
|
||||
public String getTemplateName() {
|
||||
return templateName;
|
||||
}
|
||||
|
||||
public void setTemplateName(String templateName) {
|
||||
this.templateName = templateName;
|
||||
}
|
||||
|
||||
public String getTemplateValue() {
|
||||
return templateValue;
|
||||
}
|
||||
|
||||
public void setTemplateValue(String templateValue) {
|
||||
this.templateValue = templateValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (templateName != null ? templateName.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof MailTemplateEntity)) {
|
||||
return false;
|
||||
}
|
||||
MailTemplateEntity other = (MailTemplateEntity) object;
|
||||
if ((this.templateName == null && other.templateName != null) || (this.templateName != null && !this.templateName.equals(other.templateName))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.shared.account.entity.MailTemplate[ templateName=" + templateName + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,150 +0,0 @@
|
||||
package de.muehlencord.shared.account.ui;
|
||||
|
||||
import de.muehlencord.shared.account.business.account.AccountControl;
|
||||
import de.muehlencord.shared.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.jeeutil.FacesUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import javax.ejb.EJB;
|
||||
import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.view.ViewScoped;
|
||||
import javax.inject.Named;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.web.util.WebUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Named(value = "loginView")
|
||||
@ViewScoped
|
||||
public class LoginView implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1164860380769648432L;
|
||||
|
||||
@EJB
|
||||
private AccountControl accountService;
|
||||
|
||||
private String username = null;
|
||||
private String password = null;
|
||||
private boolean rememberMe = false;
|
||||
|
||||
private String resetPasswordToken = null;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LoginView.class.getName());
|
||||
|
||||
public void authenticate() {
|
||||
|
||||
// Example using most common scenario of username/password pair:
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(getUsername(), getPassword());
|
||||
|
||||
// "Remember Me" built-in:
|
||||
token.setRememberMe(rememberMe);
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
LOGGER.info("Submitting login with username of " + username);
|
||||
|
||||
try {
|
||||
currentUser.login(token);
|
||||
// user logged in, update account entity
|
||||
AccountEntity account = accountService.getAccountEntity(username, true);
|
||||
accountService.updateLogin(account);
|
||||
|
||||
// redirect to home
|
||||
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
|
||||
String fallbackUrl = "/web/index.xhtml"; // TODO make configurable
|
||||
// ec.redirect(url);
|
||||
WebUtils.redirectToSavedRequest((ServletRequest) ec.getRequest(), (ServletResponse) ec.getResponse(), fallbackUrl);
|
||||
} catch (IOException | AuthenticationException ex) {
|
||||
// Could catch a subclass of AuthenticationException if you like
|
||||
String hint = "Error while authenticating user " + username;
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(hint, ex);
|
||||
} else {
|
||||
LOGGER.error(hint + " Reason: " + ex.toString());
|
||||
}
|
||||
FacesUtil.addErrorMessage("Login failed");
|
||||
|
||||
AccountEntity account = accountService.getAccountEntity(username, false);
|
||||
if (account != null) {
|
||||
accountService.addLoginError(account);
|
||||
}
|
||||
} finally {
|
||||
token.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
try {
|
||||
currentUser.logout();
|
||||
|
||||
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
|
||||
String url = ec.getRequestContextPath() + "/login.xhtml";
|
||||
ec.redirect(url);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public String executePasswordReset() {
|
||||
boolean passwordResetted = accountService.resetPassword(username, password, resetPasswordToken);
|
||||
if (passwordResetted) {
|
||||
// TODO add email notification on updated user account
|
||||
FacesUtil.addInfoMessage("Password resetted");
|
||||
return login();
|
||||
} else {
|
||||
// TODO add email notificaton on failed password reset
|
||||
FacesUtil.addErrorMessage("Password reset failed");
|
||||
return login();
|
||||
}
|
||||
}
|
||||
|
||||
/* **** naviation rules **** */
|
||||
public String login() {
|
||||
return "/login.xhtml"; // TODO make configurable
|
||||
}
|
||||
|
||||
/* *** getter / setter */
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String un) {
|
||||
this.username = un;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String pw) {
|
||||
this.password = pw;
|
||||
}
|
||||
|
||||
public boolean isRememberMe() {
|
||||
return rememberMe;
|
||||
}
|
||||
|
||||
public void setRememberMe(boolean rememberMe) {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
public String getResetPasswordToken() {
|
||||
return resetPasswordToken;
|
||||
}
|
||||
|
||||
public void setResetPasswordToken(String resetPasswordToken) {
|
||||
this.resetPasswordToken = resetPasswordToken;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
package de.muehlencord.shared.account.ui;
|
||||
|
||||
import de.muehlencord.shared.account.business.account.AccountControl;
|
||||
import de.muehlencord.shared.jeeutil.FacesUtil;
|
||||
import java.io.Serializable;
|
||||
import javax.ejb.EJB;
|
||||
import javax.faces.view.ViewScoped;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
*/
|
||||
@Named (value = "lostPasswordView")
|
||||
@ViewScoped
|
||||
public class LostPasswordView implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1793445795465830069L;
|
||||
|
||||
@EJB
|
||||
private AccountControl accountService;
|
||||
|
||||
private String userName;
|
||||
private boolean passwordResetStarted = false;
|
||||
|
||||
public String initPasswordReset() {
|
||||
if (accountService.initPasswordReset(userName)) {
|
||||
passwordResetStarted = true;
|
||||
FacesUtil.addInfoMessage("Password reset started, please check your email account");
|
||||
} else {
|
||||
FacesUtil.addErrorMessage("Error while resetting password. Please contact your administrator");
|
||||
}
|
||||
return "/login.xhtml"; // TODO make configurable, get from LoginView?
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public boolean getPasswordResetStarted() {
|
||||
return passwordResetStarted;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package de.muehlencord.shared.account.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.shiro.authc.credential.DefaultPasswordService;
|
||||
import org.apache.shiro.crypto.hash.DefaultHashService;
|
||||
import org.apache.shiro.crypto.hash.Sha512Hash;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
*/
|
||||
public class SecurityUtil {
|
||||
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(SecurityUtil.class.getName());
|
||||
|
||||
public static String createPassword(String clearTextPassword) {
|
||||
// TODO read values from shiro.ini
|
||||
DefaultHashService hashService = new DefaultHashService();
|
||||
hashService.setHashIterations(500000); //
|
||||
hashService.setHashAlgorithmName(Sha512Hash.ALGORITHM_NAME);
|
||||
hashService.setGeneratePublicSalt(true);
|
||||
|
||||
DefaultPasswordService passwordService = new DefaultPasswordService();
|
||||
passwordService.setHashService(hashService);
|
||||
|
||||
// try to encrypt password
|
||||
String encryptedPassword = passwordService.encryptPassword(clearTextPassword);
|
||||
LOGGER.trace(encryptedPassword);
|
||||
return encryptedPassword;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
package de.muehlencord.shared.account.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.ldap.LdapContext;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm;
|
||||
import org.apache.shiro.realm.ldap.LdapContextFactory;
|
||||
import org.apache.shiro.realm.ldap.LdapUtils;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
public class UserNameActiveDirectoryRealm extends ActiveDirectoryRealm {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(UserNameActiveDirectoryRealm.class);
|
||||
|
||||
private boolean permissionsLookupEnabled = true;
|
||||
|
||||
@Override
|
||||
protected AuthenticationInfo queryForAuthenticationInfo(AuthenticationToken token, LdapContextFactory ldapContextFactory) throws NamingException {
|
||||
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
|
||||
|
||||
LdapContext ctx = null;
|
||||
String userName = upToken.getUsername();
|
||||
try {
|
||||
if (principalSuffix != null) {
|
||||
if (!userName.contains(principalSuffix)) {
|
||||
userName += principalSuffix;
|
||||
}
|
||||
}
|
||||
|
||||
// Binds using the username and password provided by the user.
|
||||
LOGGER.debug("start creating context");
|
||||
ctx = ldapContextFactory.getLdapContext(userName, upToken.getCredentials());
|
||||
LOGGER.debug("context created");
|
||||
} finally {
|
||||
LdapUtils.closeContext(ctx);
|
||||
}
|
||||
|
||||
LOGGER.debug("building authentication info");
|
||||
AuthenticationInfo authInfo = buildAuthenticationInfo(userName, upToken.getPassword());
|
||||
LOGGER.debug("authentifaction info created");
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an {@link org.apache.shiro.authz.AuthorizationInfo} object by
|
||||
* querying the active directory LDAP context for the groups that a user is
|
||||
* a member of. The groups are then translated to role names by using the
|
||||
* configured {@link #groupRolesMap}.
|
||||
* <p/>
|
||||
* This implementation expects the <tt>principal</tt> argument to be a
|
||||
* String username.
|
||||
* <p/>
|
||||
* Subclasses can override this method to determine authorization data
|
||||
* (roles, permissions, etc) in a more complex way. Note that this default
|
||||
* implementation does not support permissions, only roles.
|
||||
*
|
||||
* @param principals the principal of the Subject whose account is being
|
||||
* retrieved.
|
||||
* @param ldapContextFactory the factory used to create LDAP connections.
|
||||
* @return the AuthorizationInfo for the given Subject principal.
|
||||
* @throws NamingException if an error occurs when searching the LDAP
|
||||
* server.
|
||||
*/
|
||||
@Override
|
||||
protected AuthorizationInfo queryForAuthorizationInfo(PrincipalCollection principals, LdapContextFactory ldapContextFactory) throws NamingException {
|
||||
Set<String> roleNames;
|
||||
if (this.permissionsLookupEnabled) {
|
||||
String username = (String) getAvailablePrincipal(principals);
|
||||
// Perform context search
|
||||
LdapContext ldapContext = ldapContextFactory.getSystemLdapContext();
|
||||
try {
|
||||
roleNames = getRoleNamesForUser(username, ldapContext);
|
||||
} finally {
|
||||
LdapUtils.closeContext(ldapContext);
|
||||
}
|
||||
} else {
|
||||
roleNames = new HashSet<>();
|
||||
}
|
||||
return buildAuthorizationInfo(roleNames);
|
||||
}
|
||||
|
||||
public boolean isPermissionsLookupEnabled() {
|
||||
return permissionsLookupEnabled;
|
||||
}
|
||||
|
||||
public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
|
||||
this.permissionsLookupEnabled = permissionsLookupEnabled;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jboss/>
|
||||
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
|
||||
<persistence-unit name="de.muehlencord.shared_shared-account_ejb_1.0-SNAPSHOTPU" transaction-type="RESOURCE_LOCAL">
|
||||
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
|
||||
<exclude-unlisted-classes>false</exclude-unlisted-classes>
|
||||
<properties>
|
||||
<property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/radius"/>
|
||||
<property name="javax.persistence.jdbc.user" value="jomu"/>
|
||||
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
|
||||
<property name="javax.persistence.jdbc.password" value="jomu"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
@ -1,44 +0,0 @@
|
||||
|
||||
package de.muehlencord.shared.account.business;
|
||||
|
||||
import de.muehlencord.shared.account.entity.ConfigEntity;
|
||||
import javax.persistence.EntityManager;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ConfigServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
private ConfigService configService;
|
||||
|
||||
@Mock
|
||||
private EntityManager entityManagerMock;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
ConfigEntity configEntity = new ConfigEntity ("account.maxFailedLogins");
|
||||
configEntity.setConfigValue("7");
|
||||
when (entityManagerMock.find(ConfigEntity.class, "account.maxFailedLogins")).thenReturn (configEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMaxFailedLogins() {
|
||||
configService.init();
|
||||
assertEquals ("maxFailedLogins", 7, configService.getMaxFailedLogins());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
package de.muehlencord.shared.account.util;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.config.IniSecurityManagerFactory;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Test;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import static org.junit.Assume.assumeNotNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
public class UserNameActiveDirectoryRealmTest {
|
||||
|
||||
@Test
|
||||
public void testUsernameLogin() {
|
||||
String userName = "user.name";
|
||||
String password = "secret";
|
||||
testLogin(userName, password);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmailaddressLogin() {
|
||||
String userName = "user.name@domain.com";
|
||||
String password = "secret";
|
||||
testLogin(userName, password);
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationException.class)
|
||||
public void testWrongUserNamePassword() {
|
||||
String userName = "test123";
|
||||
String password = "secret";
|
||||
testLogin(userName, password);
|
||||
}
|
||||
|
||||
private void testLogin(String userName, String password) throws AuthenticationException {
|
||||
assumeNotNull(UserNameActiveDirectoryRealmTest.class.getResource("/shiro.ini"));
|
||||
|
||||
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
|
||||
SecurityManager securityManager = factory.getInstance();
|
||||
SecurityUtils.setSecurityManager(securityManager);
|
||||
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
|
||||
currentUser.login(token);
|
||||
System.out.println("Logged in");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
|
||||
debug="true">
|
||||
|
||||
<appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d{ISO8601} %-5p [%c] %m%n" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<category name="de.muehlencord">
|
||||
<priority value="DEBUG"/>
|
||||
</category>
|
||||
|
||||
<category name="org.apache.shiro">
|
||||
<priority value="DEBUG"/>
|
||||
</category>
|
||||
|
||||
<category name="com.sun">
|
||||
<priority value="WARN"/>
|
||||
</category>
|
||||
|
||||
<category name="javax.xml">
|
||||
<priority value="WARN"/>
|
||||
</category>
|
||||
|
||||
<category name="org.apache.commons">
|
||||
<priority value="WARN"/>
|
||||
</category>
|
||||
|
||||
|
||||
<root>
|
||||
<level value="INFO" />
|
||||
<appender-ref ref="consoleAppender" />
|
||||
</root>
|
||||
</log4j:configuration>
|
||||
@ -1,30 +0,0 @@
|
||||
[main]
|
||||
contextFactory = org.apache.shiro.realm.ldap.JndiLdapContextFactory
|
||||
contextFactory.url = ldaps://ldap.domain.com:636
|
||||
contextFactory.systemUsername = user.name@domain.com
|
||||
contextFactory.systemPassword = secret
|
||||
contextFactory.environment[java.naming.security.protocol] = ssl
|
||||
|
||||
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
|
||||
securityManager.cacheManager = $cacheManager
|
||||
|
||||
# HashService
|
||||
hashService = org.apache.shiro.crypto.hash.DefaultHashService
|
||||
hashService.hashIterations = 500000
|
||||
hashService.hashAlgorithmName = SHA-512
|
||||
hashService.generatePublicSalt = true
|
||||
|
||||
# Password service
|
||||
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
|
||||
passwordService.hashService = $hashService
|
||||
|
||||
# LDAP Realm setup
|
||||
ldapRealm = de.muehlencord.shared.account.util.UserNameActiveDirectoryRealm
|
||||
ldapRealm.principalSuffix = @domain.com
|
||||
ldapRealm.ldapContextFactory = $contextFactory
|
||||
ldapRealm.searchBase = dc=domain,dc=com
|
||||
|
||||
# LDAP (authentication) activation
|
||||
authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy
|
||||
securityManager.realms = $ldapRealm
|
||||
securityManager.authenticator.authenticationStrategy = $authcStrategy
|
||||
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project-shared-configuration>
|
||||
<!--
|
||||
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||
The configuration is intended to be shared among all the users of project and
|
||||
therefore it is assumed to be part of version control checkout.
|
||||
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||
-->
|
||||
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||
<!--
|
||||
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||
-->
|
||||
<netbeans.checkstyle.format>true</netbeans.checkstyle.format>
|
||||
</properties>
|
||||
</project-shared-configuration>
|
||||
@ -1,15 +1,30 @@
|
||||
|
||||
<!--
|
||||
Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.muehlencord.shared</groupId>
|
||||
<artifactId>shared-configuration</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>shared</artifactId>
|
||||
<groupId>de.muehlencord</groupId>
|
||||
<version>1.0</version>
|
||||
<version>1.2.1</version>
|
||||
</parent>
|
||||
|
||||
<name>shared-configuration</name>
|
||||
@ -20,14 +35,15 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -1,10 +1,26 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import de.muehlencord.shared.configuration.converter.BooleanStringConverter;
|
||||
|
||||
/**
|
||||
* A Boolean parameter
|
||||
* @author joern@muehlencord.de
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class BooleanParameter extends Parameter<Boolean> {
|
||||
|
||||
@ -14,17 +30,18 @@ public class BooleanParameter extends Parameter<Boolean> {
|
||||
* @param name the name of the parameter
|
||||
*/
|
||||
public BooleanParameter(String name) {
|
||||
super(name, new BooleanStringConverter(), true);
|
||||
this(name, new BooleanStringConverter(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new mandatory parameter object
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param converter the converter object to convert the value of the
|
||||
* parameter to string and vice versa
|
||||
*/
|
||||
public BooleanParameter(String name, StringConverter<Boolean> converter) {
|
||||
super(name, converter, true);
|
||||
this(name, converter, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,17 +52,43 @@ public class BooleanParameter extends Parameter<Boolean> {
|
||||
*/
|
||||
public BooleanParameter(String name, boolean mandatory) {
|
||||
super(name, new BooleanStringConverter(), mandatory);
|
||||
this.addValueList(Boolean.TRUE, Boolean.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new parameter object using default string converter
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param mandatory detremines if this is a mandatory parameter or not
|
||||
* @param defaultValue the default value for this parameter
|
||||
*
|
||||
*/
|
||||
public BooleanParameter(String name, boolean mandatory, Boolean defaultValue) {
|
||||
super(name, new BooleanStringConverter(), mandatory);
|
||||
this.addValueList(Boolean.TRUE, Boolean.FALSE);
|
||||
this.setDefaultValue(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new parameter object
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param converter the converter object to convert the value of the
|
||||
* parameter to string and vice versa
|
||||
* @param mandatory detremines if this is a mandatory parameter or not
|
||||
*/
|
||||
public BooleanParameter(String name, StringConverter<Boolean> converter, boolean mandatory) {
|
||||
super(name, converter, mandatory);
|
||||
this.addValueList(Boolean.TRUE, Boolean.FALSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getDefaultValue() {
|
||||
if (defaultValue == null) {
|
||||
return false;
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,49 +1,67 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Specifies a configurable objects.
|
||||
*
|
||||
* @param <T> the type of the parameter
|
||||
* @param <V> the value of the parameter - must be the same class as the type class of the parameter
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface Configuration<T, V extends T> {
|
||||
public interface Configuration {
|
||||
|
||||
/**
|
||||
* adds a new parameter to the configuration
|
||||
*
|
||||
* @param <T> the type of the parameter to add
|
||||
* @param p the parameter to add
|
||||
* @throws ConfigurationException if the parameter cannot be added
|
||||
*/
|
||||
public void addParameter(Parameter<T> p) throws ConfigurationException;
|
||||
public <T> void addParameter(Parameter<T> p) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* sets the value of the given parameter
|
||||
*
|
||||
* @param p parameter to set
|
||||
* @param value value to set
|
||||
* @param <T> the type of the parameter to add
|
||||
* @param p the parameter to add
|
||||
* @param value the value the parameter should have
|
||||
* @throws ConfigurationException if the parameter is not defined
|
||||
*/
|
||||
public void setParameterValue(Parameter<T> p, V value) throws ConfigurationException;
|
||||
public <T> void setParameterValue(Parameter<T> p, T value) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* sets the value of parameter with given name
|
||||
*
|
||||
* @param <T> the type of the parameter to add
|
||||
* @param parameterName parameter to set
|
||||
* @param value value to set
|
||||
* @throws ConfigurationException if the parameter is not defined
|
||||
*/
|
||||
public void setParameterValue(String parameterName, V value) throws ConfigurationException;
|
||||
public <T> void setParameterValue(String parameterName, T value) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* sets the value of the given parameter
|
||||
*
|
||||
* @param <T> the type of the parameter to add
|
||||
* @param p parameter to set
|
||||
* @param value value to set
|
||||
* @throws ConfigurationException if the parameter is not defined
|
||||
*/
|
||||
public void setParameterValueByString(Parameter<T> p, String value) throws ConfigurationException;
|
||||
public <T> void setParameterValueByString(Parameter<T> p, String value) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* sets the value of the given parameter
|
||||
@ -57,22 +75,26 @@ public interface Configuration<T, V extends T> {
|
||||
/**
|
||||
* returns the value of the given parameter
|
||||
*
|
||||
* @param <T> the type of the parameter to add
|
||||
* @param p the parameter to return the value for
|
||||
* @return the value of the given parameter; null if not set
|
||||
*
|
||||
* @throws ConfigurationException if the parameter is not defined or if the value is not set
|
||||
* @throws ConfigurationException if the parameter is not defined or if the
|
||||
* value is not set
|
||||
*/
|
||||
public V getParameterValue(Parameter<T> p) throws ConfigurationException;
|
||||
public <T> T getParameterValue(Parameter<T> p) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* returns the value of the given parameter
|
||||
*
|
||||
* @param <T> the type of the parameter to add
|
||||
* @param parameterName the name of the parameter to return the value for
|
||||
* @return the value of the given parameter; null if not set
|
||||
*
|
||||
* @throws ConfigurationException if the parameter is not defined or if the value is not set
|
||||
* @throws ConfigurationException if the parameter is not defined or if the
|
||||
* value is not set
|
||||
*/
|
||||
public V getParameterValue(String parameterName) throws ConfigurationException;
|
||||
public <T> T getParameterValue(String parameterName) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* validates the configuration
|
||||
@ -84,7 +106,8 @@ public interface Configuration<T, V extends T> {
|
||||
/**
|
||||
* returns the map of parameters and values
|
||||
*
|
||||
* @param <T> the type of the parameter to add
|
||||
* @return the map of parameters and values
|
||||
*/
|
||||
public Map<Parameter<T>, V> getParameterMap();
|
||||
public <T> Map<Parameter<T>, T> getParameterMap();
|
||||
}
|
||||
|
||||
@ -1,8 +1,23 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class ConfigurationException extends Exception {
|
||||
|
||||
|
||||
@ -1,8 +1,23 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class ConverterException extends Exception {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import de.muehlencord.shared.configuration.converter.DateStringConverter;
|
||||
@ -5,7 +20,8 @@ import java.util.Date;
|
||||
|
||||
/**
|
||||
* A Date parameter
|
||||
* @author joern@muehlencord.de
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class DateParameter extends Parameter<Date> {
|
||||
|
||||
@ -32,7 +48,7 @@ public class DateParameter extends Parameter<Date> {
|
||||
* creates a new parameter object using default string converter
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param mandatory detremines if this is a mandatory parameter or not
|
||||
* @param mandatory determines if this is a mandatory parameter or not
|
||||
*/
|
||||
public DateParameter(String name, boolean mandatory) {
|
||||
super(name, new DateStringConverter(), mandatory);
|
||||
@ -43,7 +59,7 @@ public class DateParameter extends Parameter<Date> {
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param mandatory detremines if this is a mandatory parameter or not
|
||||
* @param mandatory determines if this is a mandatory parameter or not
|
||||
*/
|
||||
public DateParameter(String name, StringConverter<Date> converter, boolean mandatory) {
|
||||
super(name, converter, mandatory);
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -7,18 +22,16 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the type of the parameter
|
||||
* @param <V> the value of the parameter - must be the same class as the type class of the parameter
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class DefaultConfiguration<T, V extends T> implements Configuration<T, V> {
|
||||
public class DefaultConfiguration implements Configuration {
|
||||
|
||||
/**
|
||||
* the parameter map
|
||||
*/
|
||||
private final Map<Parameter<T>, V> parameterMap;
|
||||
private final Map<Parameter, Object> parameterMap;
|
||||
/** mapping from name to parameter */
|
||||
private final Map<String, Parameter<T>> parameterNameMap;
|
||||
private final Map<String, Parameter> parameterNameMap;
|
||||
|
||||
/**
|
||||
* creates a new instance of a configuration
|
||||
@ -33,7 +46,7 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
*
|
||||
* @return the map of parameters and values
|
||||
*/
|
||||
public Map<Parameter<T>, V> getParameterMap() {
|
||||
public Map<Parameter, Object> getParameterMap() {
|
||||
return parameterMap;
|
||||
}
|
||||
|
||||
@ -80,7 +93,7 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
* @throws ConfigurationException if the parameter is not defined
|
||||
*/
|
||||
@Override
|
||||
public void setParameterValue(Parameter<T> p, V value) throws ConfigurationException {
|
||||
public <T> void setParameterValue(Parameter<T> p, T value) throws ConfigurationException {
|
||||
if (parameterMap.containsKey(p)) {
|
||||
parameterMap.put(p, value);
|
||||
} else {
|
||||
@ -91,13 +104,14 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
/**
|
||||
* overrides parameter map with given map
|
||||
*
|
||||
* @param <T> the type of the parameter to add
|
||||
* @param map map to use
|
||||
* @throws ConfigurationException if the parameter is not defined
|
||||
*/
|
||||
public void setParameterValue (Map<Parameter<T>, V> map) throws ConfigurationException {
|
||||
for ( Map.Entry<Parameter<T>,V> entry : map.entrySet()) {
|
||||
public <T> void setParameterValue (Map<Parameter<T>, T> map) throws ConfigurationException {
|
||||
for ( Map.Entry<Parameter<T>,T> entry : map.entrySet()) {
|
||||
Parameter<T> key = entry.getKey();
|
||||
V value = entry.getValue();
|
||||
T value = entry.getValue();
|
||||
if (parameterMap.containsKey(key)) {
|
||||
parameterMap.put (key, value);
|
||||
} else {
|
||||
@ -114,7 +128,7 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
* @throws ConfigurationException if the parameter is not defined
|
||||
*/
|
||||
@Override
|
||||
public void setParameterValue(String parameterName, V value) throws ConfigurationException {
|
||||
public <T> void setParameterValue(String parameterName, T value) throws ConfigurationException {
|
||||
if (parameterNameMap.containsKey(parameterName)) {
|
||||
Parameter<T> p = parameterNameMap.get(parameterName);
|
||||
parameterMap.put(p, value);
|
||||
@ -132,10 +146,10 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
* @throws ConfigurationException if the parameter is not defined
|
||||
*/
|
||||
@Override
|
||||
public void setParameterValueByString(Parameter<T> p, String stringValue) throws ConfigurationException {
|
||||
public <T> void setParameterValueByString(Parameter<T> p, String stringValue) throws ConfigurationException {
|
||||
if (parameterMap.containsKey(p)) {
|
||||
try {
|
||||
V value = p.getStringConverter().fromString(stringValue);
|
||||
T value = p.getStringConverter().fromString(stringValue);
|
||||
parameterMap.put(p, value);
|
||||
} catch (ConverterException ex) {
|
||||
throw new ConfigurationException("Error while setting parameter value for parameter " + p.getName() + ". Reason:" + ex.getMessage(), ex);
|
||||
@ -155,11 +169,11 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
@Override
|
||||
public void setParameterValueByString(String parameterName, String stringValue) throws ConfigurationException {
|
||||
if (parameterNameMap.containsKey(parameterName)) {
|
||||
Parameter<T> p = parameterNameMap.get(parameterName);
|
||||
Parameter p = parameterNameMap.get(parameterName);
|
||||
|
||||
if (parameterMap.containsKey(p)) {
|
||||
try {
|
||||
V value = p.getStringConverter().fromString(stringValue);
|
||||
Object value = p.getStringConverter().fromString(stringValue);
|
||||
parameterMap.put(p, value);
|
||||
} catch (ConverterException ex) {
|
||||
throw new ConfigurationException("Error while setting parameter value for parameter " + p.getName() + ". Reason:" + ex.getMessage(), ex);
|
||||
@ -181,9 +195,9 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
* @throws ConfigurationException if the value cannot be determined
|
||||
*/
|
||||
@Override
|
||||
public V getParameterValue(Parameter<T> p) throws ConfigurationException {
|
||||
public <T> T getParameterValue(Parameter<T> p) throws ConfigurationException {
|
||||
if (parameterMap.containsKey(p)) {
|
||||
return parameterMap.get(p);
|
||||
return (T) parameterMap.get(p);
|
||||
} else {
|
||||
throw new ConfigurationException("Parameter " + p.getName() + " not defined");
|
||||
}
|
||||
@ -198,7 +212,7 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
* @throws ConfigurationException if the parameter is not defined or if the value is not set
|
||||
*/
|
||||
@Override
|
||||
public V getParameterValue(String parameterName) throws ConfigurationException {
|
||||
public <T> T getParameterValue(String parameterName) throws ConfigurationException {
|
||||
if (parameterNameMap.containsKey(parameterName)) {
|
||||
Parameter<T> p = parameterNameMap.get(parameterName);
|
||||
return getParameterValue(p);
|
||||
@ -215,14 +229,14 @@ public class DefaultConfiguration<T, V extends T> implements Configuration<T, V>
|
||||
*
|
||||
* @throws ConfigurationException if a check fails
|
||||
*/
|
||||
private boolean validateParameter(Parameter<T> p) throws ConfigurationException {
|
||||
private <T> boolean validateParameter(Parameter<T> p) throws ConfigurationException {
|
||||
// check if parameter is mandatory and available
|
||||
if ((p.isMandatory()) && (parameterMap.get(p) == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if parameter has required parameters and if these are set
|
||||
V parameterValue = getParameterValue(p);
|
||||
T parameterValue = getParameterValue(p);
|
||||
if (parameterValue != null) {
|
||||
for (Parameter rp : p.getRequiredParameter()) {
|
||||
if (getParameterValue(rp) == null) {
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import de.muehlencord.shared.configuration.converter.IntegerStringConverter;
|
||||
@ -5,7 +20,7 @@ import de.muehlencord.shared.configuration.converter.IntegerStringConverter;
|
||||
/**
|
||||
* A Integer parameter
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class IntegerParameter extends Parameter<Integer> {
|
||||
|
||||
|
||||
@ -1,39 +1,75 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> type of parameter
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public abstract class Parameter<T> {
|
||||
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(Parameter.class);
|
||||
|
||||
/** the name of the parameter */
|
||||
private String name;
|
||||
/** the long description of this parameter */
|
||||
private String description;
|
||||
/** boolean flag if this is a mandatory parameter or not */
|
||||
private boolean mandatory;
|
||||
/** the string converter to convert the object to string and back again */
|
||||
private StringConverter<T> stringConverter;
|
||||
/** list of mandatory parameters, if this parameter is active */
|
||||
private List<Parameter<?>> requiredParameters;
|
||||
/** optional validator */
|
||||
private Validator<T> validator;
|
||||
/**
|
||||
* the name of the parameter
|
||||
*/
|
||||
protected String name;
|
||||
/**
|
||||
* the long description of this parameter
|
||||
*/
|
||||
protected String description;
|
||||
/**
|
||||
* boolean flag if this is a mandatory parameter or not
|
||||
*/
|
||||
protected boolean mandatory;
|
||||
/**
|
||||
* the string converter to convert the object to string and back again
|
||||
*/
|
||||
protected StringConverter<T> stringConverter;
|
||||
/**
|
||||
* list of mandatory parameters, if this parameter is active
|
||||
*/
|
||||
protected List<Parameter<?>> requiredParameters; // TODO rename to depending parmeter
|
||||
/**
|
||||
* optional validator
|
||||
*/
|
||||
protected Validator<T> validator;
|
||||
/**
|
||||
* optional value list
|
||||
*/
|
||||
protected List<T> valueList;
|
||||
/**
|
||||
* the default value
|
||||
*/
|
||||
protected T defaultValue;
|
||||
|
||||
/**
|
||||
* creates a new mandatory string parameter object
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param converter the converter object to convert the value of the
|
||||
* parameter to string and vice versa
|
||||
*/
|
||||
public Parameter(String name, StringConverter<T> converter) {
|
||||
this.name = name;
|
||||
@ -42,13 +78,16 @@ public abstract class Parameter<T> {
|
||||
this.stringConverter = converter;
|
||||
this.requiredParameters = new LinkedList<>();
|
||||
this.validator = null;
|
||||
this.valueList = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new string parameter object. If the parameter is mandatory or not can be specified.
|
||||
* creates a new string parameter object. If the parameter is mandatory or
|
||||
* not can be specified.
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param converter the converter object to convert the value of the
|
||||
* parameter to string and vice versa
|
||||
* @param mandatory determines if this is a mandatory parameter or not
|
||||
*/
|
||||
public Parameter(String name, StringConverter<T> converter, boolean mandatory) {
|
||||
@ -60,7 +99,8 @@ public abstract class Parameter<T> {
|
||||
* creates a new string parameter object.
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param converter the converter object to convert the value of the
|
||||
* parameter to string and vice versa
|
||||
* @param description the long text description of this parameter
|
||||
* @param mandatory determines if this is a mandatory parameter or not
|
||||
*/
|
||||
@ -124,22 +164,58 @@ public abstract class Parameter<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true, if the given value is part of the possible value list or if the given value list is true
|
||||
* @param validator the validator to set
|
||||
*/
|
||||
public void setValidator(Validator<T> validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
public void addValueList(T... values) {
|
||||
if (valueList == null) {
|
||||
valueList = new ArrayList<>();
|
||||
}
|
||||
valueList.addAll(Arrays.asList(values));
|
||||
}
|
||||
|
||||
public List<T> getValueList() {
|
||||
List<T> returnList = new ArrayList<>();
|
||||
if (valueList != null) {
|
||||
returnList.addAll(valueList);
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true, if the given value is part of the possible value list or if
|
||||
* the given value list is true
|
||||
*
|
||||
* @param value the value to validate
|
||||
* @return true if no value list is defined or value is part of the value list; false otherwise
|
||||
* @return true if no value list is defined or value is part of the value
|
||||
* list; false otherwise
|
||||
*/
|
||||
public boolean isValid(T value) {
|
||||
if (validator == null) {
|
||||
return true;
|
||||
} else {
|
||||
try {
|
||||
validator.validate(value);
|
||||
if (valueList == null) {
|
||||
if (validator == null) {
|
||||
return true;
|
||||
} catch (ValidationException ex) {
|
||||
LOGGER.debug (ex.toString(), ex);
|
||||
return false;
|
||||
} else {
|
||||
try {
|
||||
validator.validate(value);
|
||||
return true;
|
||||
} catch (ValidationException ex) {
|
||||
LOGGER.debug(ex.toString(), ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return valueList.contains(value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,10 +239,4 @@ public abstract class Parameter<T> {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param validator the validator to set
|
||||
*/
|
||||
public void setValidator(Validator<T> validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import java.net.URI;
|
||||
@ -5,7 +20,7 @@ import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public abstract class ParameterFactory {
|
||||
|
||||
|
||||
@ -1,9 +1,24 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the class type of the parameter value to convert
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface StringConverter<T> {
|
||||
|
||||
|
||||
@ -1,10 +1,26 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import de.muehlencord.shared.configuration.converter.StringStringConverter;
|
||||
|
||||
/**
|
||||
* A String parameter
|
||||
* @author joern@muehlencord.de
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class StringParameter extends Parameter<String> {
|
||||
|
||||
@ -17,11 +33,23 @@ public class StringParameter extends Parameter<String> {
|
||||
super(name, new StringStringConverter(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new mandatory parameter object using default string converter
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param defaultValue the default value of the parameter to set.
|
||||
*/
|
||||
public StringParameter(String name, String defaultValue) {
|
||||
super(name, new StringStringConverter(), true);
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new mandatory parameter object
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param converter the converter object to convert the value of the
|
||||
* parameter to string and vice versa
|
||||
*/
|
||||
public StringParameter(String name, StringConverter<String> converter) {
|
||||
super(name, converter, true);
|
||||
@ -41,7 +69,8 @@ public class StringParameter extends Parameter<String> {
|
||||
* creates a new parameter object
|
||||
*
|
||||
* @param name the name of the parameter
|
||||
* @param converter the converter object to convert the value of the parameter to string and vice versa
|
||||
* @param converter the converter object to convert the value of the
|
||||
* parameter to string and vice versa
|
||||
* @param mandatory detremines if this is a mandatory parameter or not
|
||||
*/
|
||||
public StringParameter(String name, StringConverter<String> converter, boolean mandatory) {
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
import de.muehlencord.shared.configuration.converter.URIStringConverter;
|
||||
@ -5,7 +20,7 @@ import java.net.URI;
|
||||
|
||||
/**
|
||||
* A URI parameter
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class URIParameter extends Parameter<URI> {
|
||||
|
||||
|
||||
@ -1,8 +1,23 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class ValidationException extends Exception {
|
||||
|
||||
|
||||
@ -1,9 +1,24 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the type of the validator
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface Validator<T> {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration.converter;
|
||||
|
||||
import de.muehlencord.shared.configuration.ConverterException;
|
||||
@ -6,7 +21,7 @@ import static java.lang.Boolean.parseBoolean;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class BooleanStringConverter implements StringConverter<Boolean> {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration.converter;
|
||||
|
||||
import de.muehlencord.shared.configuration.ConverterException;
|
||||
@ -8,7 +23,7 @@ import java.util.Locale;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class DateStringConverter implements StringConverter<Date> {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration.converter;
|
||||
|
||||
import de.muehlencord.shared.configuration.ConverterException;
|
||||
@ -6,7 +21,7 @@ import static java.lang.Integer.parseInt;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class IntegerStringConverter implements StringConverter<Integer> {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration.converter;
|
||||
|
||||
import de.muehlencord.shared.configuration.ConverterException;
|
||||
@ -5,7 +20,7 @@ import de.muehlencord.shared.configuration.StringConverter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class StringStringConverter implements StringConverter<String> {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration.converter;
|
||||
|
||||
import de.muehlencord.shared.configuration.ConverterException;
|
||||
@ -7,7 +22,7 @@ import static java.net.URI.create;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class URIStringConverter implements StringConverter<URI> {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration.validator;
|
||||
|
||||
import de.muehlencord.shared.configuration.ValidationException;
|
||||
@ -5,7 +20,7 @@ import de.muehlencord.shared.configuration.Validator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class IntgerRangeValidator implements Validator<Integer> {
|
||||
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.configuration.validator;
|
||||
|
||||
import de.muehlencord.shared.configuration.ValidationException;
|
||||
@ -8,7 +23,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class StringValueListValidator implements Validator<String> {
|
||||
|
||||
|
||||
97
db/pom.xml
Normal file
97
db/pom.xml
Normal file
@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.muehlencord.shared</groupId>
|
||||
<artifactId>shared-db</artifactId>
|
||||
<packaging>ejb</packaging>
|
||||
|
||||
<parent>
|
||||
<artifactId>shared</artifactId>
|
||||
<groupId>de.muehlencord</groupId>
|
||||
<version>1.2.1</version>
|
||||
</parent>
|
||||
|
||||
<name>shared-db</name>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>shared-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax</groupId>
|
||||
<artifactId>javaee-web-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
<!-- Dev Tools -->
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
<version>1.18.12</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- create EJB version 3.1 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-ejb-plugin</artifactId>
|
||||
<configuration>
|
||||
<ejbVersion>3.1</ejbVersion>
|
||||
<excludes>
|
||||
<exclude>**/persistence.xml</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.ejb.Lock;
|
||||
import javax.ejb.LockType;
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Order;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
* @param <T> the entity this controller will serve. All objects returned are of
|
||||
* this type.
|
||||
*/
|
||||
public abstract class AbstractController<T extends Serializable> extends CommonAbstractController {
|
||||
|
||||
private final Class<T> entityClass;
|
||||
|
||||
protected AbstractController(Class<T> clazz) {
|
||||
this.entityClass = clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* general find method
|
||||
*
|
||||
* @param id the primary key of the entity to search for.
|
||||
* @return the found entity instance or null if the entity does not exist
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public T find(Object id) {
|
||||
return em.find(entityClass, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* general find method with the option to initialize lists/sets of 1:n
|
||||
* relations during the query.
|
||||
*
|
||||
* @param id the primary key of the entity to search for.
|
||||
* @param subGraphItems the name of the subgraph items to initialize.
|
||||
* Typically this is the name of the 1:n set or list.
|
||||
* @return the found entity instance or null if the entity does not exist
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public T find(Object id, String... subGraphItems) {
|
||||
EntityGraph<T> graph = this.em.createEntityGraph(entityClass);
|
||||
for (String subGraphItem : subGraphItems) {
|
||||
graph.addSubgraph(subGraphItem);
|
||||
}
|
||||
|
||||
Map<String, Object> hints = new HashMap<>();
|
||||
hints.put("javax.persistence.loadgraph", graph);
|
||||
|
||||
return em.find(entityClass, id, hints);
|
||||
}
|
||||
|
||||
@Lock(LockType.READ)
|
||||
public List<T> find(String queryName, Map<String, Object> parameterMap) {
|
||||
Query query = em.createNamedQuery(queryName);
|
||||
parameterMap.entrySet().forEach(entry -> query.setParameter(entry.getKey(), entry.getValue()));
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a list of all entities.
|
||||
*
|
||||
* @return a list of all entities.
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public List<T> findAll() throws ControllerException {
|
||||
return findAll(new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a list of all entities.
|
||||
*
|
||||
* @param orderFields the list of field names to order the result by.
|
||||
* @return a list of all entities.
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public List<T> findAll(String... orderFields) throws ControllerException {
|
||||
return findAll(Arrays.asList(orderFields));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param orderFields the list of field names to order the result by.
|
||||
* @return a list of all entities.
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public List<T> findAll(List<String> orderFields) throws ControllerException {
|
||||
return findAll(entityClass, orderFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* searches for entities by specifying a filter map. The map contains a
|
||||
* field name and field value.
|
||||
*
|
||||
* @param filters the filters to apply
|
||||
* @param orderFields the fields to order the result by.
|
||||
* @return a list of found entities.
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public List<T> find(Map<String, Object> filters, List<String> orderFields) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<T> criteria = cb.createQuery(entityClass);
|
||||
|
||||
final Root<T> r = criteria.from(entityClass);
|
||||
Predicate filterCondition = getFilterCondition(cb, r, filters);
|
||||
if (filterCondition != null) {
|
||||
criteria.where(filterCondition);
|
||||
}
|
||||
List<Order> orderList = new ArrayList<>();
|
||||
orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(r.get(field))));
|
||||
final TypedQuery<T> query = em.createQuery(criteria.orderBy(orderList));
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
36
db/src/main/java/de/muehlencord/shared/db/ApplicationPU.java
Normal file
36
db/src/main/java/de/muehlencord/shared/db/ApplicationPU.java
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Qualifier
|
||||
@Retention(RUNTIME)
|
||||
@Target({METHOD, FIELD, PARAMETER, TYPE})
|
||||
public @interface ApplicationPU {
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
import javax.inject.Inject;
|
||||
import javax.interceptor.AroundInvoke;
|
||||
import javax.interceptor.Interceptor;
|
||||
import javax.interceptor.InvocationContext;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.transaction.Transactional;
|
||||
import static javax.transaction.Transactional.TxType.REQUIRED;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Transactional(value = REQUIRED)
|
||||
@Interceptor
|
||||
@Priority(value = ApplicationTransactionJoinInterceptor.PRIORITY)
|
||||
public class ApplicationTransactionJoinInterceptor {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationTransactionJoinInterceptor.class);
|
||||
|
||||
// attach behind the interceptor of the container
|
||||
public static final int PRIORITY = Interceptor.Priority.PLATFORM_BEFORE + 250;
|
||||
|
||||
@Inject
|
||||
@ApplicationPU
|
||||
private EntityManager em;
|
||||
|
||||
@AroundInvoke
|
||||
public Object joinTransaction(InvocationContext context) throws Exception {
|
||||
if (em == null) {
|
||||
return context.proceed();
|
||||
} else {
|
||||
if (em.isJoinedToTransaction()) {
|
||||
LOGGER.trace("transaction already joined");
|
||||
} else {
|
||||
LOGGER.trace("joining transaction");
|
||||
em.joinTransaction();
|
||||
}
|
||||
}
|
||||
return context.proceed();
|
||||
}
|
||||
}
|
||||
133
db/src/main/java/de/muehlencord/shared/db/Audit.java
Normal file
133
db/src/main/java/de/muehlencord/shared/db/Audit.java
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
public class Audit implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -955765069412891842L;
|
||||
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "valid_from")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime validFrom;
|
||||
|
||||
@Column(name = "valid_to")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime validTo;
|
||||
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "created_on")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime createdOn;
|
||||
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "created_by")
|
||||
private String createdBy;
|
||||
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "last_updated_on")
|
||||
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
|
||||
@JsonSerialize(using = LocalDateTimeSerializer.class)
|
||||
private LocalDateTime lastUpdatedOn;
|
||||
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "last_updated_by")
|
||||
private String lastUpdatedBy;
|
||||
|
||||
public Audit() {
|
||||
this.validFrom = LocalDateTime.now(ZoneOffset.UTC);
|
||||
this.lastUpdatedOn = LocalDateTime.now(ZoneOffset.UTC);
|
||||
this.createdOn = LocalDateTime.now(ZoneOffset.UTC);
|
||||
}
|
||||
|
||||
public Audit withNewAudit(String userName) {
|
||||
LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
|
||||
this.setCreatedBy(userName);
|
||||
this.setCreatedOn(now);
|
||||
this.setLastUpdatedBy(userName);
|
||||
this.setLastUpdatedOn(now);
|
||||
this.setValidFrom(now);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit withEndDate() {
|
||||
return withEndDate (LocalDateTime.now(ZoneOffset.UTC));
|
||||
}
|
||||
|
||||
private Audit withEndDate(LocalDateTime endDate) {
|
||||
this.setValidTo(endDate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit withValidFrom(final LocalDateTime validFrom) {
|
||||
this.validFrom = validFrom;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit withValidTo(final LocalDateTime validTo) {
|
||||
this.validTo = validTo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit withCreatedOn(final LocalDateTime createdOn) {
|
||||
this.createdOn = createdOn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit withCreatedBy(final String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit withLastUpdatedOn(final LocalDateTime lastUpdatedOn) {
|
||||
this.lastUpdatedOn = lastUpdatedOn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit withLastUpdatedBy(final String lastUpdatedBy) {
|
||||
this.lastUpdatedBy = lastUpdatedBy;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
64
db/src/main/java/de/muehlencord/shared/db/AuditListener.java
Normal file
64
db/src/main/java/de/muehlencord/shared/db/AuditListener.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Does not work, cannot Spring independent inject current username - implemented in AbstractController manually
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class AuditListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuditListener.class);
|
||||
|
||||
// @PrePersist
|
||||
public void prePersist(Auditable auditable) {
|
||||
Audit audit = auditable.getAudit();
|
||||
|
||||
if (audit == null) {
|
||||
audit = new Audit();
|
||||
auditable.setAudit(audit);
|
||||
}
|
||||
|
||||
LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
|
||||
audit.setCreatedOn(now);
|
||||
audit.setLastUpdatedOn(now);
|
||||
// audit.setCreatedBy(LoggedUser.get()); // TODO where to get the user from
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("prePersist executed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// @PreUpdate
|
||||
public void preUpdate(Auditable auditable) {
|
||||
Audit audit = auditable.getAudit();
|
||||
|
||||
// TODO where to get the user from
|
||||
LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
|
||||
audit.setLastUpdatedOn(now);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("preUpdate executed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
27
db/src/main/java/de/muehlencord/shared/db/Auditable.java
Normal file
27
db/src/main/java/de/muehlencord/shared/db/Auditable.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface Auditable {
|
||||
|
||||
Audit getAudit();
|
||||
|
||||
void setAudit(Audit audit);
|
||||
}
|
||||
@ -0,0 +1,730 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import de.muehlencord.shared.util.DateUtil;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import javax.ejb.Lock;
|
||||
import javax.ejb.LockType;
|
||||
import javax.ejb.TransactionAttribute;
|
||||
import javax.ejb.TransactionAttributeType;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Order;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.transaction.Transactional;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public abstract class CommonAbstractController {
|
||||
|
||||
/**
|
||||
* the entity manager to use
|
||||
*/
|
||||
@Inject
|
||||
@ApplicationPU
|
||||
protected EntityManager em;
|
||||
|
||||
// required for unit testing
|
||||
public void setEntityManager (EntityManager em) {
|
||||
this.em = em;
|
||||
}
|
||||
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> T find(Class<T> clazz, Object id) {
|
||||
return em.find(clazz, id);
|
||||
}
|
||||
|
||||
private <T> EntityGraph getEntityGraph(Class<T> clazz, String... subGraphItems) {
|
||||
EntityGraph graph = this.em.createEntityGraph(clazz);
|
||||
if (subGraphItems != null) {
|
||||
for (String subGraphItem : subGraphItems) {
|
||||
graph.addSubgraph(subGraphItem);
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> T find(Class<T> clazz, Object id, String... subGraphItems) {
|
||||
EntityGraph graph = getEntityGraph(clazz, subGraphItems);
|
||||
Map hints = new HashMap<>();
|
||||
hints.put("javax.persistence.loadgraph", graph);
|
||||
|
||||
T entity = (T) em.find(clazz, id, hints);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> List<T> find(Class<T> clazz, Map<String, Object> filters, List<String> orderFields, String... subGraphItems) {
|
||||
return find(clazz, filters, orderFields, 0, 0, subGraphItems);
|
||||
}
|
||||
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> List<T> find(Class<T> clazz, Map<String, Object> filters, List<String> orderFields, int limit, int offset, String... subGraphItems) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<T> criteria = cb.createQuery(clazz);
|
||||
|
||||
final Root<T> r = criteria.from(clazz);
|
||||
Predicate filterCondition = getFilterCondition(cb, r, filters);
|
||||
if (filterCondition != null) {
|
||||
criteria.where(filterCondition);
|
||||
}
|
||||
List<Order> orderList = new ArrayList<>();
|
||||
orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(r.get(field))));
|
||||
final TypedQuery<T> query = em.createQuery(criteria.orderBy(orderList))
|
||||
.setFirstResult(offset);
|
||||
if (limit > 0) {
|
||||
query.setMaxResults(limit);
|
||||
}
|
||||
|
||||
EntityGraph graph = getEntityGraph(clazz, subGraphItems);
|
||||
query.setHint("javax.persistence.loadgraph", graph);
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> List<T> find(Class<T> clazz, List<SearchFilter> filters, List<String> orderFields, String... subGraphItems) throws ControllerException {
|
||||
return find(clazz, filters, orderFields, 0, 0);
|
||||
}
|
||||
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> List<T> find(Class<T> clazz, List<SearchFilter> filters, List<String> orderFields, int limit, int offset, String... subGraphItems) throws ControllerException {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<T> criteria = cb.createQuery(clazz);
|
||||
|
||||
final Root<T> r = criteria.from(clazz);
|
||||
Predicate filterCondition = getFilterCondition(cb, r, filters);
|
||||
if (filterCondition != null) {
|
||||
criteria.where(filterCondition);
|
||||
}
|
||||
List<Order> orderList = new ArrayList<>();
|
||||
if (orderFields != null) {
|
||||
orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(r.get(field))));
|
||||
}
|
||||
final TypedQuery<T> query = em.createQuery(criteria.orderBy(orderList)).setFirstResult(offset);
|
||||
if (limit > 0) {
|
||||
query.setMaxResults(limit);
|
||||
}
|
||||
|
||||
if (!ArrayUtils.isEmpty(subGraphItems)) {
|
||||
EntityGraph graph = getEntityGraph(clazz, subGraphItems);
|
||||
query.setHint("javax.persistence.loadgraph", graph);
|
||||
}
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the type of the entity to search for
|
||||
* @param entityClass the entity class to return
|
||||
* @return a list of all entities found
|
||||
* @throws ControllerException if the search cannot be executed.
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> List<T> findAll(Class<T> entityClass) throws ControllerException {
|
||||
return findAll(entityClass, new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the type of the entity to search for
|
||||
* @param entityClass the entity class to return
|
||||
* @param orderFields the fields to order the result by.
|
||||
* @return a list of all entities found
|
||||
* @throws ControllerException if the search cannot be executed.
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> List<T> findAll(Class<T> entityClass, String... orderFields) throws ControllerException {
|
||||
return findAll(entityClass, Arrays.asList(orderFields));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param <T> the type of the entity to search for
|
||||
* @param entityClass the entity class to return
|
||||
* @param orderFields the fields to order the result by.
|
||||
* @return a list of all entities found
|
||||
* @throws ControllerException if the search cannot be executed.
|
||||
*/
|
||||
@Lock(LockType.READ)
|
||||
public <T extends Serializable> List<T> findAll(Class<T> entityClass, List<String> orderFields) throws ControllerException {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<T> criteria = cb.createQuery(entityClass);
|
||||
|
||||
final Root<T> r = criteria.from(entityClass);
|
||||
|
||||
if (EndDateable.class.isAssignableFrom(entityClass.getClass())) {
|
||||
Date now = DateUtil.getCurrentTimeInUTC();
|
||||
List<SearchFilter> searchFilter = new ArrayList<>();
|
||||
searchFilter.add(new DefaultSearchFilter("validFrom", Comparator.GREATER_OR_EQUAL_THAN, now));
|
||||
searchFilter.add(new DefaultSearchFilter("validTo", Comparator.LESS_THAN, now));
|
||||
Predicate filterCondition = getFilterCondition(cb, r, searchFilter);
|
||||
criteria.where(filterCondition);
|
||||
}
|
||||
|
||||
List<Order> orderList = new ArrayList<>();
|
||||
orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(r.get(field))));
|
||||
final TypedQuery<T> query = em.createQuery(criteria.orderBy(orderList));
|
||||
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
/* **** standard crud options *** */
|
||||
/**
|
||||
* updates the audit field of the entity class.
|
||||
*
|
||||
* @param audit the audit to apply
|
||||
* @param onCreate specifies, whether the the update should be applied for a new entity or not. If yes, then also the createdBy /createdOn fields are updated. Otherwise these fields are skipped.
|
||||
* @param changedBy the username to apply
|
||||
* @return an updated audit object to use for the updated entity.
|
||||
* @throws ControllerException if the audit object cannot be updated
|
||||
*/
|
||||
public Audit applyAuditChanges(Audit audit, boolean onCreate, String changedBy) throws ControllerException {
|
||||
if (audit == null) {
|
||||
audit = new Audit();
|
||||
}
|
||||
if (onCreate) {
|
||||
audit.setCreatedBy(changedBy);
|
||||
audit.setCreatedOn(LocalDateTime.now(ZoneOffset.UTC));
|
||||
}
|
||||
audit.setLastUpdatedBy(changedBy);
|
||||
audit.setLastUpdatedOn(LocalDateTime.now(ZoneOffset.UTC));
|
||||
|
||||
return audit;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates an new entity or if the entity already exists updates it
|
||||
*
|
||||
* @param <T> the type of the entity to search for
|
||||
* @param entity the entity to create or update
|
||||
* @param createdBy the username to apply write into the audit history
|
||||
* @return the entity after it has been written to the database.
|
||||
* @throws ControllerException if the the creation or update of the entity fails.
|
||||
*/
|
||||
@TransactionAttribute(TransactionAttributeType.REQUIRED)
|
||||
@Transactional
|
||||
@Lock(LockType.WRITE)
|
||||
public <T extends IdentifiableEntity> T createOrUpdate(T entity, String createdBy) throws ControllerException {
|
||||
if (entity.getId() == null) {
|
||||
create(entity, createdBy);
|
||||
return entity;
|
||||
} else {
|
||||
return update(entity, createdBy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* creates an new entity.
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param entity the entity to create or update
|
||||
* @param createdBy the username to apply write into the audit history
|
||||
* @return the entity after it has been written to the database.
|
||||
* @throws ControllerException if the the creation fails
|
||||
*/
|
||||
@TransactionAttribute(TransactionAttributeType.REQUIRED)
|
||||
@Transactional
|
||||
@Lock(LockType.WRITE)
|
||||
public <T> T create(T entity, String createdBy) throws ControllerException {
|
||||
if (Auditable.class.isAssignableFrom(entity.getClass())) {
|
||||
Audit audit = ((Auditable) entity).getAudit();
|
||||
((Auditable) entity).setAudit(applyAuditChanges(audit, true, createdBy));
|
||||
}
|
||||
if (EndDateable.class.isAssignableFrom(entity.getClass())) {
|
||||
EndDateable endDateable = (EndDateable) entity;
|
||||
if (endDateable.getValidity() == null) {
|
||||
Validity validity = new Validity();
|
||||
endDateable.setValidity(validity);
|
||||
}
|
||||
if (endDateable.getValidity().getValidFrom() == null) {
|
||||
endDateable.getValidity().setValidFrom(DateUtil.getCurrentTimeInUTC());
|
||||
}
|
||||
}
|
||||
em.persist(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* updates an existing entity.
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param entity the entity to update
|
||||
* @param updatedBy the username to apply write into the audit history
|
||||
* @return the entity after it has been written to the database.
|
||||
* @throws ControllerException if the the updates fails
|
||||
*/
|
||||
private <T extends Serializable> T executeUpdate(T entity, String updatedBy) throws ControllerException {
|
||||
T currentEntity = attach(entity);
|
||||
if (Auditable.class.isAssignableFrom(currentEntity.getClass())) {
|
||||
Audit audit = ((Auditable) currentEntity).getAudit();
|
||||
((Auditable) currentEntity).setAudit(applyAuditChanges(audit, false, updatedBy));
|
||||
}
|
||||
|
||||
if (EndDateable.class.isAssignableFrom(currentEntity.getClass())) {
|
||||
// end date existing entity
|
||||
EndDateable endDateable = (EndDateable) currentEntity;
|
||||
Validity validity = endDateable.getValidity();
|
||||
if (validity == null) {
|
||||
validity = new Validity();
|
||||
validity.setValidFrom(DateUtil.getCurrentTimeInUTC());
|
||||
}
|
||||
validity.setValidTo(DateUtil.getCurrentTimeInUTC());
|
||||
|
||||
endDateable.setValidity(validity);
|
||||
// and create new entity instead
|
||||
}
|
||||
|
||||
return currentEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* updates an existing entity.
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param entity the entity to update
|
||||
* @param updatedBy the username to apply write into the audit history
|
||||
* @return the entity after it has been written to the database.
|
||||
* @throws ControllerException if the the updates fails
|
||||
*/
|
||||
@TransactionAttribute(TransactionAttributeType.REQUIRED)
|
||||
@Transactional
|
||||
@Lock(LockType.WRITE)
|
||||
public <T extends Serializable> T update(T entity, String updatedBy) throws ControllerException {
|
||||
T currentEntity = executeUpdate(entity, updatedBy);
|
||||
if (EndDateable.class.isAssignableFrom(entity.getClass())) {
|
||||
T newEntity = EntityUtil.cloneToNewEntity(currentEntity);
|
||||
em.merge(currentEntity);
|
||||
return create(newEntity, updatedBy);
|
||||
} else {
|
||||
// if it is not enddatable, just update it (already done above)
|
||||
// and save it
|
||||
return em.merge(currentEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an entity from the database. If the entity implements the {@link EndDateable} interface, the entity is not deleted but marked as deleted (end date set).
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param entity the entity to delete
|
||||
* @param deletedBy the username to apply write into the audit history
|
||||
* @throws ControllerException if the deletion fails.
|
||||
*/
|
||||
@TransactionAttribute(TransactionAttributeType.REQUIRED)
|
||||
@Transactional
|
||||
@Lock(LockType.WRITE)
|
||||
public <T extends Serializable> void delete(T entity, String deletedBy) throws ControllerException {
|
||||
// if the entity is endDateable just set the validToDate to now intead of executing the deletion
|
||||
if (EndDateable.class.isAssignableFrom(entity.getClass())) {
|
||||
T currentEntity = executeUpdate(entity, deletedBy);
|
||||
em.merge(currentEntity);
|
||||
} else {
|
||||
em.remove(attach(entity));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* attaches the given entity
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param entity the entity to attach
|
||||
* @return the entity after it has been attached
|
||||
*/
|
||||
public <T extends Serializable> T attach(T entity) {
|
||||
return em.merge(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes an entity.
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param entity the entity after it has been refreshed.
|
||||
*/
|
||||
public <T extends Serializable> void refresh(T entity) {
|
||||
em.refresh(entity);
|
||||
}
|
||||
|
||||
/* *** filter methods *** */
|
||||
/**
|
||||
* Creates a filter condition.
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param cb the CriteriaBuilder to use
|
||||
* @param root the root to use
|
||||
* @param filters the filters to use
|
||||
* @return the created filter condition
|
||||
*/
|
||||
protected <T extends Serializable> Predicate getFilterCondition(CriteriaBuilder cb, Root<T> root, Map<String, Object> filters) {
|
||||
return getFilterCondition(cb, root, filters, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a filter condition.
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param cb the CriteriaBuilder to use
|
||||
* @param root the root to use
|
||||
* @param filters the filters to use
|
||||
* @param excludeFilters the exclude filters to apply. Entities which match these filters, are not taken into the result list.
|
||||
* @return the created filter condition
|
||||
*/
|
||||
protected <T extends Serializable> Predicate getFilterCondition(CriteriaBuilder cb, Root<T> root, Map<String, Object> filters, Map<String, Object> excludeFilters) {
|
||||
Predicate includeFilterCondition = getFilterCondition(null, cb, root, filters, true);
|
||||
Predicate excludeFilterCondition = getFilterCondition(null, cb, root, excludeFilters, false);
|
||||
|
||||
if ((includeFilterCondition == null) && (excludeFilterCondition == null)) {
|
||||
return null;
|
||||
} else if (includeFilterCondition == null) {
|
||||
return excludeFilterCondition;
|
||||
} else if (excludeFilterCondition == null) {
|
||||
return includeFilterCondition;
|
||||
} else {
|
||||
return cb.and(includeFilterCondition, excludeFilterCondition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* extends the given filterCondition by the additional filters
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param filterCondition the current filter condition
|
||||
* @param cb the criteria builder to use
|
||||
* @param root the root of the object to search for
|
||||
* @param filters the filters to apply
|
||||
* @param include if set to true, the filter is used as include filter (equals, in). If set to false, the filter is inverted and used as exclude filter (not equals, not in etc)
|
||||
* @return the created filter condition
|
||||
*/
|
||||
protected <T extends Serializable> Predicate getFilterCondition(Predicate filterCondition, CriteriaBuilder cb, Root<T> root, Map<String, Object> filters, boolean include) {
|
||||
String wildCard = "%";
|
||||
if (filters != null) {
|
||||
for (Map.Entry<String, Object> filter : filters.entrySet()) {
|
||||
if (!"".equals(filter.getValue())) {
|
||||
Path<String> path = getPathElement(root, filter);
|
||||
|
||||
// check for differnt types
|
||||
// 1st String, either from Enum Status or from other free text string
|
||||
if (filter.getValue() == null) {
|
||||
Predicate predicate;
|
||||
if (include) {
|
||||
predicate = cb.isNull(path);
|
||||
} else {
|
||||
predicate = cb.isNotNull(path);
|
||||
}
|
||||
filterCondition = addFilterCondition(cb, filterCondition, predicate);
|
||||
} else if (String.class.equals(filter.getValue().getClass())) {
|
||||
switch (filter.getKey()) {
|
||||
default:
|
||||
String filterValue = filter.getValue().toString();
|
||||
Predicate predicate;
|
||||
if (filterValue.equals("{NULL}")) {
|
||||
if (include) {
|
||||
predicate = cb.isNull(path);
|
||||
} else {
|
||||
predicate = cb.isNotNull(path);
|
||||
}
|
||||
} else {
|
||||
filterValue = filterValue.trim();
|
||||
filterValue = filterValue.replace("?", "_");
|
||||
filterValue = filterValue.replace("*", "%");
|
||||
|
||||
String[] values = filterValue.split("\\s+"); // split by whitespaces
|
||||
Predicate[] partSearchPredicates = new Predicate[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
String value = wildCard + values[i] + wildCard;
|
||||
if (include) {
|
||||
partSearchPredicates[i] = cb.like(cb.upper(path), value.toUpperCase(Locale.US), '\\');
|
||||
} else {
|
||||
partSearchPredicates[i] = cb.notLike(cb.upper(path), value.toUpperCase(Locale.US), '\\');
|
||||
}
|
||||
}
|
||||
predicate = cb.and(partSearchPredicates); // all parts must be available
|
||||
}
|
||||
filterCondition = addFilterCondition(cb, filterCondition, predicate);
|
||||
}
|
||||
} // 2nd for arrays, received from e.g. project selections
|
||||
else if (filter.getValue().getClass().isArray()) {
|
||||
Predicate condition = null;
|
||||
Object[] values = (Object[]) filter.getValue();
|
||||
if (values.length > 0) {
|
||||
for (Object value : values) {
|
||||
if (include) {
|
||||
Predicate equalPredicate = cb.equal(path, value);
|
||||
if (condition == null) {
|
||||
condition = equalPredicate;
|
||||
} else {
|
||||
condition = cb.or(condition, equalPredicate);
|
||||
}
|
||||
} else {
|
||||
Predicate equalPredicate = cb.notEqual(path, value);
|
||||
if (condition == null) {
|
||||
condition = equalPredicate;
|
||||
} else {
|
||||
condition = cb.and(condition, equalPredicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
filterCondition = addFilterCondition(cb, filterCondition, condition);
|
||||
}
|
||||
} else { // at last object comparison
|
||||
if (include) {
|
||||
filterCondition = addFilterCondition(cb, filterCondition, cb.equal(path, filter.getValue()));
|
||||
} else {
|
||||
filterCondition = addFilterCondition(cb, filterCondition, cb.notEqual(path, filter.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return filterCondition;
|
||||
}
|
||||
|
||||
protected <T extends Serializable> Predicate getFilterCondition(CriteriaBuilder cb, Root<T> root, List<SearchFilter> searchFilter) throws ControllerException {
|
||||
return getFilterCondition(null, cb, root, searchFilter);
|
||||
}
|
||||
|
||||
protected <T extends Serializable> Predicate getFilterCondition(final Predicate filterCondition, CriteriaBuilder cb, Root<T> root, List<SearchFilter> searchFilter) throws ControllerException {
|
||||
Predicate returnCondition = filterCondition;
|
||||
for (SearchFilter currentFilter : searchFilter) {
|
||||
if (currentFilter.getComparator() == null) {
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, "Comparator must not be null");
|
||||
}
|
||||
if (currentFilter.getFieldName() == null) {
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, "Fieldname must not be null");
|
||||
}
|
||||
|
||||
Path<String> path = getPathElement(root, currentFilter);
|
||||
|
||||
if (currentFilter.getSearchValue() == null) {
|
||||
Predicate predicate;
|
||||
switch (currentFilter.getComparator()) {
|
||||
case EQUAL:
|
||||
predicate = cb.isNull(path);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
predicate = cb.isNotNull(path);
|
||||
default:
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, currentFilter.getComparator() + " not supported for searchValue null");
|
||||
}
|
||||
returnCondition = addFilterCondition(cb, returnCondition, predicate);
|
||||
} else if (currentFilter.getSearchValue() instanceof String) {
|
||||
String searchValue = (String) currentFilter.getSearchValue();
|
||||
String wildCard = "%";
|
||||
Predicate predicate;
|
||||
switch (currentFilter.getComparator()) {
|
||||
case EQUAL:
|
||||
predicate = cb.equal(path, searchValue);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
predicate = cb.notEqual(path, searchValue);
|
||||
break;
|
||||
case CONTAINS:
|
||||
String likeValue = wildCard + searchValue.toUpperCase(Locale.US) + wildCard;
|
||||
predicate = cb.like(cb.upper(path), likeValue, '\\');
|
||||
break;
|
||||
default:
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, currentFilter.getComparator() + "not support for searchValue " + searchValue);
|
||||
}
|
||||
returnCondition = addFilterCondition(cb, returnCondition, predicate);
|
||||
} else if (currentFilter.getSearchValue() instanceof Date) {
|
||||
// TODO - support Date, LocaleDate, LocalTime, LocalDateTime, ZoneDateTime
|
||||
Date searchValue = (Date) currentFilter.getSearchValue();
|
||||
Predicate predicate;
|
||||
Path<Date> datePath = root.<Date>get(currentFilter.getFieldName());
|
||||
switch (currentFilter.getComparator()) {
|
||||
case EQUAL:
|
||||
predicate = cb.equal(datePath, searchValue);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
predicate = cb.notEqual(datePath, searchValue);
|
||||
break;
|
||||
case LESS_THAN:
|
||||
predicate = cb.lessThan(datePath, searchValue);
|
||||
break;
|
||||
case LESS_OR_EQUAL_THAN:
|
||||
predicate = cb.lessThanOrEqualTo(datePath, searchValue);
|
||||
break;
|
||||
case GREATER_THAN:
|
||||
predicate = cb.greaterThan(datePath, searchValue);
|
||||
break;
|
||||
case GREATER_OR_EQUAL_THAN:
|
||||
predicate = cb.greaterThanOrEqualTo(datePath, searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, currentFilter.getComparator() + "not support for searchValue " + searchValue);
|
||||
}
|
||||
returnCondition = addFilterCondition(cb, returnCondition, predicate);
|
||||
} else if (currentFilter.getSearchValue() instanceof Boolean) {
|
||||
Boolean searchValue = (Boolean) currentFilter.getSearchValue();
|
||||
Path<Boolean> booleanPath = root.<Boolean>get(currentFilter.getFieldName());
|
||||
Predicate predicate;
|
||||
switch (currentFilter.getComparator()) {
|
||||
case EQUAL:
|
||||
predicate = cb.equal(booleanPath, searchValue);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
predicate = cb.notEqual(booleanPath, searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, currentFilter.getComparator() + "not support for searchValue " + searchValue);
|
||||
}
|
||||
returnCondition = addFilterCondition(cb, returnCondition, predicate);
|
||||
} else if (currentFilter.getSearchValue() instanceof UUID) {
|
||||
UUID searchValue = (UUID) currentFilter.getSearchValue();
|
||||
Path<UUID> booleanPath = root.<UUID>get(currentFilter.getFieldName());
|
||||
Predicate predicate;
|
||||
switch (currentFilter.getComparator()) {
|
||||
case EQUAL:
|
||||
predicate = cb.equal(booleanPath, searchValue);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
predicate = cb.notEqual(booleanPath, searchValue);
|
||||
break;
|
||||
default:
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, currentFilter.getComparator() + "not support for searchValue " + searchValue);
|
||||
}
|
||||
returnCondition = addFilterCondition(cb, returnCondition, predicate);
|
||||
} else if (currentFilter.getSearchValue() instanceof List) {
|
||||
List<Object> searchValues = (List) currentFilter.getSearchValue();
|
||||
Predicate predicate = null;
|
||||
if (!searchValues.isEmpty()) {
|
||||
for (Object obj : searchValues) {
|
||||
SearchFilter sf = new DefaultSearchFilter(currentFilter.getFieldName(), currentFilter.getComparator(), obj);
|
||||
List<SearchFilter> localFilterList = new ArrayList<>();
|
||||
localFilterList.add(sf);
|
||||
Predicate localPredicate = getFilterCondition(null, cb, root, localFilterList);
|
||||
predicate = orFilterCondition(cb, predicate, localPredicate);
|
||||
}
|
||||
returnCondition = addFilterCondition(cb, returnCondition, predicate);
|
||||
}
|
||||
// Path
|
||||
} else {
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, "Filter for " + currentFilter.getSearchValue().getClass().getSimpleName() + " not yet implemented");
|
||||
}
|
||||
} // for all filters
|
||||
|
||||
return returnCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a filter condition to an existing condition
|
||||
*
|
||||
* @param cb the builder to use
|
||||
* @param filterCondition the existing filter condition
|
||||
* @param addCondition the condition to add to the existing condition.
|
||||
* @return an updated filter condition.
|
||||
*/
|
||||
protected Predicate addFilterCondition(CriteriaBuilder cb, Predicate filterCondition, Predicate addCondition) {
|
||||
if (addCondition == null) {
|
||||
return filterCondition;
|
||||
}
|
||||
if (filterCondition == null) {
|
||||
filterCondition = addCondition;
|
||||
} else {
|
||||
filterCondition = cb.and(filterCondition, addCondition);
|
||||
}
|
||||
return filterCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a filter condition to an existing condition
|
||||
*
|
||||
* @param cb the builder to use
|
||||
* @param filterCondition the existing filter condition
|
||||
* @param orCondition the condition to add to the existing condition.
|
||||
* @return an updated filter condition.
|
||||
*/
|
||||
protected Predicate orFilterCondition(CriteriaBuilder cb, Predicate filterCondition, Predicate orCondition) {
|
||||
if (orCondition == null) {
|
||||
return filterCondition;
|
||||
}
|
||||
if (filterCondition == null) {
|
||||
filterCondition = orCondition;
|
||||
} else {
|
||||
filterCondition = cb.or(filterCondition, orCondition);
|
||||
}
|
||||
return filterCondition;
|
||||
}
|
||||
|
||||
private <T extends Serializable> Path<String> getPathElement(Root<T> root, Map.Entry<String, Object> filter) {
|
||||
String[] pathElements = StringUtils.split(filter.getKey(), '.');
|
||||
Path<String> path = null;
|
||||
for (String element : pathElements) {
|
||||
if (path == null) {
|
||||
path = root.get(element);
|
||||
} else {
|
||||
path = path.get(element);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private <T extends Serializable> Path<String> getPathElement(Root<T> root, SearchFilter filter) {
|
||||
String[] pathElements = StringUtils.split(filter.getFieldName(), '.');
|
||||
Path<String> path = null;
|
||||
for (String element : pathElements) {
|
||||
if (path == null) {
|
||||
path = root.get(element);
|
||||
} else {
|
||||
path = path.get(element);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns null, if the list is empty or null itself.Returns the one element if there is exactly one element in the list. Otherwise an exception is thrown
|
||||
*
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param entityList the list to validate
|
||||
* @return the one and only element of the provided list
|
||||
* @throws ControllerException if the list contains more than one element.
|
||||
*/
|
||||
public <T> T ensureSingleElement(List<T> entityList) throws ControllerException {
|
||||
if ((entityList == null) || (entityList.isEmpty())) {
|
||||
return null;
|
||||
}
|
||||
if (entityList.size() > 1) {
|
||||
throw new ControllerException(ControllerException.CAUSE_TOO_MANY_ROWS, "More than one element found in list - expected exactly one");
|
||||
}
|
||||
return entityList.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
34
db/src/main/java/de/muehlencord/shared/db/Comparator.java
Normal file
34
db/src/main/java/de/muehlencord/shared/db/Comparator.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public enum Comparator {
|
||||
|
||||
EQUAL,
|
||||
NOT_EQUAL,
|
||||
CONTAINS,
|
||||
LESS_THAN,
|
||||
LESS_OR_EQUAL_THAN,
|
||||
GREATER_THAN,
|
||||
GREATER_OR_EQUAL_THAN;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import javax.ejb.ApplicationException;
|
||||
|
||||
/**
|
||||
* Generic exception if an exception inside a Controller class occurs
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@ApplicationException(rollback = true)
|
||||
public class ControllerException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 5190280225284514859L;
|
||||
public static final int INTERNAL_ERROR = 0;
|
||||
public static final int CAUSE_ALREADY_EXISTS = 1;
|
||||
public static final int CAUSE_NOT_FOUND = 2;
|
||||
public static final int CAUSE_CANNOT_PERSIST = 3;
|
||||
public static final int CAUSE_TOO_MANY_ROWS = 4;
|
||||
public static final int CAUSE_CANNOT_DELETE = 5;
|
||||
public static final int INVALID_FILTER = 6;
|
||||
|
||||
private final int causeCode;
|
||||
|
||||
/**
|
||||
* Creates a new instance of <code>ControllerException</code> without detail message.
|
||||
*
|
||||
* @param cause the reason code
|
||||
* @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method.
|
||||
*/
|
||||
public ControllerException(int cause, String message) {
|
||||
super(message);
|
||||
this.causeCode = cause;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param causeCode the reason code
|
||||
* @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method.
|
||||
*
|
||||
* @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). (A {@code null} value is permitted, and
|
||||
* indicates that the cause is nonexistent or unknown.)
|
||||
*/
|
||||
public ControllerException(int causeCode, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.causeCode = causeCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the cause code
|
||||
*
|
||||
* @return the cause code
|
||||
*/
|
||||
public int getCauseCode() {
|
||||
return causeCode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class DefaultSearchFilter implements SearchFilter {
|
||||
|
||||
private final String fieldName;
|
||||
private final Comparator comparator;
|
||||
private final Object searchValue;
|
||||
private final Operator operator;
|
||||
|
||||
public DefaultSearchFilter(String fieldName, Comparator comparator, Object fieldValue) {
|
||||
this.fieldName = fieldName;
|
||||
this.comparator = comparator;
|
||||
this.searchValue = fieldValue;
|
||||
this.operator = null;
|
||||
}
|
||||
|
||||
public DefaultSearchFilter(String fieldName, Comparator comparator, Operator operator, Object... fieldValue) {
|
||||
this.fieldName = fieldName;
|
||||
this.comparator = comparator;
|
||||
List<Object> searchValues = new ArrayList();
|
||||
searchValues.addAll(Arrays.asList(fieldValue));
|
||||
this.searchValue = searchValues;
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator getComparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSearchValue() {
|
||||
return searchValue;
|
||||
}
|
||||
|
||||
public Operator getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
}
|
||||
29
db/src/main/java/de/muehlencord/shared/db/EndDateable.java
Normal file
29
db/src/main/java/de/muehlencord/shared/db/EndDateable.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
/**
|
||||
* Enddateable entities are not deleted but an enddate is set to "now"
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface EndDateable<T> {
|
||||
|
||||
void setValidity(Validity v);
|
||||
|
||||
Validity getValidity();
|
||||
|
||||
}
|
||||
119
db/src/main/java/de/muehlencord/shared/db/EntityUtil.java
Normal file
119
db/src/main/java/de/muehlencord/shared/db/EntityUtil.java
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import de.muehlencord.shared.util.DateUtil;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import javax.persistence.Id;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class EntityUtil {
|
||||
|
||||
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(EntityUtil.class);
|
||||
|
||||
public static Field getIdField(Class<?> entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var f : entity.getDeclaredFields()) {
|
||||
Id id = null;
|
||||
Annotation[] as = f.getAnnotations();
|
||||
for (Annotation a : as) {
|
||||
if (a.annotationType() == Id.class) {
|
||||
id = (Id) a;
|
||||
}
|
||||
}
|
||||
|
||||
if (id != null) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
// iterated over all fields, not found
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T setIdValue(T entity, Object fieldValue) throws ControllerException {
|
||||
Field field = getIdField(entity.getClass());
|
||||
|
||||
if (field == null) {
|
||||
return entity;
|
||||
}
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("id column of {} is {}", entity.getClass().getSimpleName(), field.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
PropertyDescriptor pd = new PropertyDescriptor(field.getName(), entity.getClass());
|
||||
pd.getWriteMethod().invoke(entity, fieldValue);
|
||||
return entity;
|
||||
} catch (IllegalAccessException | InvocationTargetException | IntrospectionException ex) {
|
||||
String hint = "Error setting value of field " + field.getName() + " to " + fieldValue;
|
||||
if (fieldValue != null) {
|
||||
hint += " of type " + fieldValue.getClass().getSimpleName();
|
||||
}
|
||||
throw new ControllerException(ControllerException.INTERNAL_ERROR, hint, ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* clones the given entity and updates related fields so the entity appears as new.The following changes are
|
||||
* executed
|
||||
* <ul>
|
||||
* <li>the Id field of the entity is set to null</li>
|
||||
* <li>if the entity is auditable, the audit is set to null.</li>
|
||||
* <li>if the entity is enddatable, validTo is set to null and validFrom is set to current sysdate (in UTC)
|
||||
* </ul>
|
||||
*
|
||||
* @param <T> the entity to be cloned - must implement serializeable to be cloned
|
||||
* @param entity the entity to be cloned - must implement serializeable to be cloned
|
||||
* @return the cloned entity with updated fields as described above
|
||||
* @throws de.muehlencord.shared.db.ControllerException if the id value cannot be set to null
|
||||
*/
|
||||
public static <T extends Serializable> T cloneToNewEntity(T entity) throws ControllerException {
|
||||
T newEntity = SerializationUtils.clone(entity);
|
||||
|
||||
// ensure id column is set to null
|
||||
newEntity = setIdValue(newEntity, null);
|
||||
|
||||
// remove audit if class is auditable - it is a new clone
|
||||
if (Auditable.class.isAssignableFrom(newEntity.getClass())) {
|
||||
((Auditable) newEntity).setAudit(null);
|
||||
}
|
||||
|
||||
// set new valid dates if class is enddateable
|
||||
if (EndDateable.class.isAssignableFrom(newEntity.getClass())) {
|
||||
Validity validity = new Validity();
|
||||
validity.setValidFrom(DateUtil.getCurrentTimeInUTC());
|
||||
validity.setValidTo(null);
|
||||
((EndDateable) newEntity).setValidity(validity);
|
||||
}
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface IdentifiableEntity extends Serializable{
|
||||
|
||||
Object getId();
|
||||
|
||||
String getIdString();
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
@MappedSuperclass
|
||||
public abstract class NumericallyIdentifiedEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Basic(optional = false)
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
26
db/src/main/java/de/muehlencord/shared/db/Operator.java
Normal file
26
db/src/main/java/de/muehlencord/shared/db/Operator.java
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public enum Operator {
|
||||
|
||||
AND, OR;
|
||||
|
||||
}
|
||||
30
db/src/main/java/de/muehlencord/shared/db/SearchFilter.java
Normal file
30
db/src/main/java/de/muehlencord/shared/db/SearchFilter.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface SearchFilter {
|
||||
|
||||
Comparator getComparator();
|
||||
|
||||
String getFieldName();
|
||||
|
||||
Object getSearchValue();
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import javax.ejb.Stateless;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Stateless
|
||||
public class StandardController extends CommonAbstractController {
|
||||
|
||||
|
||||
|
||||
}
|
||||
59
db/src/main/java/de/muehlencord/shared/db/Validity.java
Normal file
59
db/src/main/java/de/muehlencord/shared/db/Validity.java
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Embeddable
|
||||
public class Validity implements Serializable {
|
||||
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "valid_from")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date validFrom;
|
||||
@Column(name = "valid_to")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date validTo;
|
||||
|
||||
public Date getValidFrom() {
|
||||
return validFrom;
|
||||
}
|
||||
|
||||
public void setValidFrom(Date validFrom) {
|
||||
this.validFrom = validFrom;
|
||||
}
|
||||
|
||||
public Date getValidTo() {
|
||||
return validTo;
|
||||
}
|
||||
|
||||
public void setValidTo(Date validTo) {
|
||||
this.validTo = validTo;
|
||||
}
|
||||
|
||||
}
|
||||
109
db/src/test/java/de/muehlencord/shared/db/CounterEntity.java
Normal file
109
db/src/test/java/de/muehlencord/shared/db/CounterEntity.java
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "counter")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "CounterEntity.findAll", query = "SELECT c FROM CounterEntity c")
|
||||
, @NamedQuery(name = "CounterEntity.findByCounterKey", query = "SELECT c FROM CounterEntity c WHERE c.counterKey = :counterKey")
|
||||
, @NamedQuery(name = "CounterEntity.findByCounterDefinition", query = "SELECT c FROM CounterEntity c WHERE c.counterDefinition = :counterDefinition")})
|
||||
public class CounterEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5104103828013760003L;
|
||||
|
||||
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
@Column(name = "counter_key")
|
||||
private String counterKey;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 100)
|
||||
@Column(name = "counter_definition")
|
||||
private String counterDefinition;
|
||||
|
||||
public CounterEntity() {
|
||||
}
|
||||
|
||||
public CounterEntity(String counterKey) {
|
||||
this.counterKey = counterKey;
|
||||
}
|
||||
|
||||
public CounterEntity(String counterKey, String counterDefinition) {
|
||||
this.counterKey = counterKey;
|
||||
this.counterDefinition = counterDefinition;
|
||||
}
|
||||
|
||||
public String getCounterKey() {
|
||||
return counterKey;
|
||||
}
|
||||
|
||||
public void setCounterKey(String counterKey) {
|
||||
this.counterKey = counterKey;
|
||||
}
|
||||
|
||||
public String getCounterDefinition() {
|
||||
return counterDefinition;
|
||||
}
|
||||
|
||||
public void setCounterDefinition(String counterDefinition) {
|
||||
this.counterDefinition = counterDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (counterKey != null ? counterKey.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof CounterEntity)) {
|
||||
return false;
|
||||
}
|
||||
CounterEntity other = (CounterEntity) object;
|
||||
if ((this.counterKey == null && other.counterKey != null) || (this.counterKey != null && !this.counterKey.equals(other.counterKey))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.office.entity.core.CounterEntity[ counterKey=" + counterKey + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class EntityUtilTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EntityUtilTest.class);
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
Field idField = EntityUtil.getIdField(CounterEntity.class);
|
||||
assertNotNull(idField);
|
||||
assertEquals("counterKey", idField.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetIdNull() throws IllegalArgumentException, IllegalAccessException, ControllerException {
|
||||
CounterEntity counter = new CounterEntity();
|
||||
counter.setCounterDefinition("counterDefinitionValue");
|
||||
counter.setCounterKey("counterKeyValue");
|
||||
LOGGER.info("Counter after creation: {}", counter.toString());
|
||||
|
||||
Field idField = EntityUtil.getIdField(CounterEntity.class);
|
||||
|
||||
assertNotNull(idField);
|
||||
|
||||
assertEquals("counterKey", idField.getName());
|
||||
// assertEquals("counterKeyValue", idField.get(counter));
|
||||
counter = EntityUtil.setIdValue(counter, null);
|
||||
// assertNull (idField.get (counter));
|
||||
assertNull (counter.getCounterKey());
|
||||
|
||||
LOGGER.info("Counter after update: {}", counter.toString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
211
db/src/test/java/de/muehlencord/shared/db/TestEntity.java
Normal file
211
db/src/test/java/de/muehlencord/shared/db/TestEntity.java
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "address")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "AddressEntity.findAll", query = "SELECT a FROM AddressEntity a"),
|
||||
@NamedQuery(name = "AddressEntity.findByStreet", query = "SELECT a FROM AddressEntity a WHERE a.street = :street"),
|
||||
@NamedQuery(name = "AddressEntity.findByPostalArea", query = "SELECT a FROM AddressEntity a WHERE a.postalArea = :postalArea"),
|
||||
@NamedQuery(name = "AddressEntity.findByCity", query = "SELECT a FROM AddressEntity a WHERE a.city = :city"),
|
||||
@NamedQuery(name = "AddressEntity.findByValidFrom", query = "SELECT a FROM AddressEntity a WHERE a.validFrom = :validFrom"),
|
||||
@NamedQuery(name = "AddressEntity.findByValidTo", query = "SELECT a FROM AddressEntity a WHERE a.validTo = :validTo")})
|
||||
public class TestEntity implements Serializable, Auditable, EndDateable<TestEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Id
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
private UUID id;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 200)
|
||||
@Column(name = "street")
|
||||
private String street;
|
||||
@Size(max = 10)
|
||||
@Column(name = "street_number")
|
||||
private String streetNumber;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 10)
|
||||
@Column(name = "postal_area")
|
||||
private String postalArea;
|
||||
@Basic(optional = false)
|
||||
@NotNull
|
||||
@Size(min = 1, max = 50)
|
||||
@Column(name = "city")
|
||||
private String city;
|
||||
@Column(name = "government_district")
|
||||
private String governmentDistrict;
|
||||
@Min(value = -90)
|
||||
@Max(value = 90)
|
||||
@Column(name = "latitude")
|
||||
private Double latitude;
|
||||
@Min(value = -180)
|
||||
@Max(value = 180)
|
||||
@Column(name = "longitude")
|
||||
private Double longitude;
|
||||
|
||||
@Embedded
|
||||
private Validity validity;
|
||||
@Embedded
|
||||
private Audit audit;
|
||||
|
||||
public TestEntity() {
|
||||
// empty constructor required for JPA
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getIdString() {
|
||||
if (id == null) {
|
||||
return "unknown";
|
||||
} else {
|
||||
return id.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public String getStreetNumber() {
|
||||
return streetNumber;
|
||||
}
|
||||
|
||||
public void setStreetNumber(String streetNumber) {
|
||||
this.streetNumber = streetNumber;
|
||||
}
|
||||
|
||||
public String getPostalArea() {
|
||||
return postalArea;
|
||||
}
|
||||
|
||||
public void setPostalArea(String postalArea) {
|
||||
this.postalArea = postalArea;
|
||||
}
|
||||
|
||||
public String getGovernmentDistrict() {
|
||||
return governmentDistrict;
|
||||
}
|
||||
|
||||
public void setGovernmentDistrict(String governmentDistrict) {
|
||||
this.governmentDistrict = governmentDistrict;
|
||||
}
|
||||
|
||||
public Double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
public void setLatitude(Double latitude) {
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
public Double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
public void setLongitude(Double longitude) {
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Validity getValidity() {
|
||||
return validity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValidity(Validity validity) {
|
||||
this.validity = validity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Audit getAudit() {
|
||||
return audit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAudit(Audit audit) {
|
||||
this.audit = audit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 0;
|
||||
hash += (id != null ? id.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
// TODO: Warning - this method won't work in the case the id fields are not set
|
||||
if (!(object instanceof TestEntity)) {
|
||||
return false;
|
||||
}
|
||||
TestEntity other = (TestEntity) object;
|
||||
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "de.muehlencord.office.entity.party.AddressEntity[ id=" + id + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,24 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>shared</artifactId>
|
||||
<groupId>de.muehlencord</groupId>
|
||||
<version>1.0</version>
|
||||
<version>1.2.1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>de.muehlencord.shared</groupId>
|
||||
<artifactId>shared-jeeutil</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>ejb</packaging>
|
||||
|
||||
<name>shared-jeeutil</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.inversoft</groupId>
|
||||
<artifactId>prime-jwt</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<groupId>io.fusionauth</groupId>
|
||||
<artifactId>fusionauth-jwt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax</groupId>
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil;
|
||||
|
||||
import javax.faces.application.FacesMessage;
|
||||
import javax.faces.application.FacesMessage.Severity;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class DefaultUIMessage implements UIMessage {
|
||||
|
||||
private static final long serialVersionUID = 3417186732917401077L;
|
||||
|
||||
public static DefaultUIMessage create(String message) {
|
||||
return new DefaultUIMessage(UIMessageType.INFO, message, null);
|
||||
}
|
||||
|
||||
public static DefaultUIMessage createWarning(String message) {
|
||||
return new DefaultUIMessage(UIMessageType.WARNING, message, null);
|
||||
}
|
||||
|
||||
public static DefaultUIMessage create(UIMessageType messageType, String message, String detail) {
|
||||
return new DefaultUIMessage(messageType, message, detail);
|
||||
}
|
||||
|
||||
private UIMessageType messageType;
|
||||
private String message;
|
||||
private String detail;
|
||||
|
||||
public DefaultUIMessage(UIMessageType messageType, String message) {
|
||||
this.messageType = messageType;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
private DefaultUIMessage(UIMessageType messageType, String message, String detail) {
|
||||
this.messageType = messageType;
|
||||
this.message = message;
|
||||
this.detail = detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UIMessageType getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDetail() {
|
||||
return (detail == null) ? "" : detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacesMessage getFacesMessage() {
|
||||
return getFacesMessage(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacesMessage getFacesMessage(String prefix) {
|
||||
|
||||
Severity severity;
|
||||
switch (getMessageType()) {
|
||||
case INFO:
|
||||
severity = FacesMessage.SEVERITY_INFO;
|
||||
break;
|
||||
case WARNING:
|
||||
severity = FacesMessage.SEVERITY_WARN;
|
||||
break;
|
||||
case ERROR:
|
||||
severity = FacesMessage.SEVERITY_WARN;
|
||||
break;
|
||||
default:
|
||||
severity = FacesMessage.SEVERITY_ERROR;
|
||||
break;
|
||||
}
|
||||
String summary;
|
||||
if ((prefix == null) || (prefix.equals(""))) {
|
||||
summary = getMessage();
|
||||
} else {
|
||||
summary = prefix + ": " + getMessage();
|
||||
}
|
||||
return new FacesMessage(severity, summary, getDetail());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,68 +1,342 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil;
|
||||
|
||||
import java.util.List;
|
||||
import javax.faces.application.FacesMessage;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
/**
|
||||
* Helper class for java faces application.
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public abstract class FacesUtil {
|
||||
|
||||
private FacesUtil() {
|
||||
// hide constructor of abstract class
|
||||
}
|
||||
private FacesUtil() {
|
||||
// hide constructor of abstract class
|
||||
}
|
||||
|
||||
public static void addMessage(FacesMessage message) {
|
||||
FacesContext.getCurrentInstance().addMessage("messages", message);
|
||||
}
|
||||
/**
|
||||
* returns true, if the current request is in the request phase. False otherwise.
|
||||
*
|
||||
* @return true, if the current request is in the request phase. False otherwise.
|
||||
*/
|
||||
public static boolean isRenderRequest() {
|
||||
return !FacesContext.getCurrentInstance().getRenderResponse();
|
||||
}
|
||||
|
||||
public static void addMessage(String clientId, FacesMessage message) {
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
/**
|
||||
* returns true, if the current request is in the response phase. True otherwise.
|
||||
*
|
||||
* @return true, if the current request is in the response phase. True otherwise.
|
||||
*/
|
||||
public static boolean isRenderResponse() {
|
||||
return FacesContext.getCurrentInstance().getRenderResponse();
|
||||
}
|
||||
|
||||
public static void addInfoMessage(String summary) {
|
||||
addInfoMessage(summary, "");
|
||||
}
|
||||
/**
|
||||
* Adds the given message to the "messages" object
|
||||
*
|
||||
* @param message the message to display
|
||||
* @deprecated use addMessage(clientId, message) or addGlobalMessage(message) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addMessage(FacesMessage message) {
|
||||
FacesContext.getCurrentInstance().addMessage("messages", message);
|
||||
}
|
||||
|
||||
public static void addInfoMessage(String summary, String detail) {
|
||||
addInfoMessage("messages", summary, detail);
|
||||
}
|
||||
/**
|
||||
* Adds the given message to the object with the id specified by clientId.
|
||||
*
|
||||
* @param clientId the id of the object to bind the message to.
|
||||
* @param message the message to display
|
||||
*/
|
||||
public static void addMessage(String clientId, FacesMessage message) {
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
|
||||
public static void addInfoMessage(String clientId, String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
/**
|
||||
* Adds the given message to the object with the id specified by clientId.
|
||||
*
|
||||
* @param clientId the id of the object to bind the message to.
|
||||
* @param message the message to display
|
||||
*/
|
||||
public static void addMessage(String clientId, FacesMessage message, boolean validationFailed) {
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
if (validationFailed) {
|
||||
FacesContext.getCurrentInstance().validationFailed();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addErrorMessage(String summary) {
|
||||
addErrorMessage("warnings", summary, "");
|
||||
}
|
||||
/**
|
||||
* Adds the given message as global message.
|
||||
*
|
||||
* @param message the message to display
|
||||
*/
|
||||
public static void addGlobalMessage(FacesMessage message) {
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
public static void addErrorMessage(String summary, String detail) {
|
||||
addErrorMessage("warnings", summary, detail);
|
||||
}
|
||||
/**
|
||||
* Adds the given message as global message with severity "Information".
|
||||
*
|
||||
* @param summary the message to add
|
||||
*/
|
||||
public static void addGlobalInfoMessage(String summary) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, summary, null);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
public static void addErrorMessage(String clientId, String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
/**
|
||||
* Adds the given message as global message with severity "Information".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addGlobalInfoMessage(String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
public static void addWarningMessage(String summary) {
|
||||
addWarningMessage("warnings", summary, "");
|
||||
}
|
||||
/**
|
||||
* Adds the given message as global message with severity "Warning".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
*/
|
||||
public static void addGlobalWarningMessage(String summary) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, summary, null);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
public static void addWarningMessage(String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage("warnings", message);
|
||||
}
|
||||
/**
|
||||
* Adds the given message as global message with severity "Warning".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addGlobalWarningMessage(String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
public static void addWarningMessage(String clientId, String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
/**
|
||||
* Adds the given message as global message with severity "Error".
|
||||
*
|
||||
* @param summary the message to display
|
||||
*/
|
||||
public static void addGlobalErrorMessage(String summary) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, null);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
public static void addFatalMessage(String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage("warnings", message);
|
||||
/**
|
||||
* Adds the given message as global message with severity "Error".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addGlobalErrorMessage(String summary, String detail) {
|
||||
addGlobalErrorMessage(summary, detail, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message as global message with severity "Error".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
* @param valiationFailed if set to true, the method calls currentInstance().validationFailed() to invalidate the current request.
|
||||
*/
|
||||
public static void addGlobalErrorMessage(String summary, String detail, boolean valiationFailed) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
if (valiationFailed) {
|
||||
FacesContext.getCurrentInstance().validationFailed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message as global message with severity "Fatal".
|
||||
*
|
||||
* @param summary the message to display
|
||||
*/
|
||||
public static void addGlobalFatalMessage(String summary) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, null);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message as global message with severity "Fatal".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addGlobalFatalMessage(String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message to the object with id "messages" and severity "Information".
|
||||
*
|
||||
* @param summary the message to display
|
||||
* @deprecated use addInfoMessage(clientId, summary) or addGlobalInfoMessage instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addInfoMessage(String summary) {
|
||||
addInfoMessage(summary, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message to the object with id "messages" and severity "Information".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
* @deprecated use addInfoMessage (clientId, summary, detail) or addGlobalInfoMessage(summary, detail) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addInfoMessage(String summary, String detail) {
|
||||
addInfoMessage("messages", summary, detail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message with severity "Info" to the object with the id specified by clientId.
|
||||
*
|
||||
* @param clientId the id of the object to bind the message to.
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addInfoMessage(String clientId, String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message to the object with id "warnings" and severity "Error".
|
||||
*
|
||||
* @param summary the message to display
|
||||
* @deprecated use addErrorMessage (clientId, summary, detail) or addGlobalErrorMessage(summary, detail) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addErrorMessage(String summary) {
|
||||
addErrorMessage("warnings", summary, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message to the object with id "warnings" and severity "Error".
|
||||
*
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
* @deprecated use addErrorMessage (clientId, summary, detail) or addGlobalErrorMessage(summary, detail) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addErrorMessage(String summary, String detail) {
|
||||
addErrorMessage("warnings", summary, detail);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message with severity "Error" to the object with the id specified by clientId.
|
||||
*
|
||||
* @param clientId the id of the object to bind the message to.
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addErrorMessage(String clientId, String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message to the object with id "warnings" and severity "Warning".
|
||||
*
|
||||
* @param summary the message to display
|
||||
* @deprecated use addWarningMessage (clientId, summary, detail) or addGlobalWarningMessage(summary, detail) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addWarningMessage(String summary) {
|
||||
addWarningMessage("warnings", summary, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message to the object with id "warnings" and severity "Warning".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
* @deprecated use addWarningMessage (clientId, summary, detail) or addGlobalWarningMessage(summary, detail) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addWarningMessage(String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage("warnings", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message with severity "Warning" to the object with the id specified by clientId.
|
||||
*
|
||||
* @param clientId the id of the object to bind the message to.
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addWarningMessage(String clientId, String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message to the object with id "warnings" and severity "Fatal".
|
||||
*
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
* @deprecated use addFatalMessage (clientId, summary, detail) or addGlobalFatalMessage(summary, detail) instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void addFatalMessage(String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage("warnings", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given message with severity "Fatal" to the object with the id specified by clientId.
|
||||
*
|
||||
* @param clientId the id of the object to bind the message to.
|
||||
* @param summary the summary message to display
|
||||
* @param detail the detailed message to display
|
||||
*/
|
||||
public static void addFatalMessage(String clientId, String summary, String detail) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_FATAL, summary, detail);
|
||||
FacesContext.getCurrentInstance().addMessage(clientId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param messages the messages to add
|
||||
*/
|
||||
public static void addMessages(List<UIMessage> messages) {
|
||||
messages.stream().map(msg -> msg.getFacesMessage()).forEach(msg -> {
|
||||
if (msg.getSeverity() == FacesMessage.SEVERITY_ERROR) {
|
||||
FacesUtil.addGlobalErrorMessage(msg.getSummary(), msg.getDetail());
|
||||
} else if (msg.getSeverity() == FacesMessage.SEVERITY_WARN) {
|
||||
FacesUtil.addGlobalWarningMessage(msg.getSummary(), msg.getDetail());
|
||||
} else if (msg.getSeverity() == FacesMessage.SEVERITY_FATAL) {
|
||||
FacesUtil.addGlobalFatalMessage(msg.getSummary(), msg.getDetail());
|
||||
} else {
|
||||
FacesUtil.addGlobalInfoMessage(msg.getSummary(), msg.getDetail());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -7,12 +22,14 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
/**
|
||||
* http://octagen.at/2014/10/postgresql-custom-data-types-enum-in-hibernate/
|
||||
*
|
||||
* @author joern@muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public abstract class GenericEnumType<T, E extends Enum<E>> implements UserType, Serializable {
|
||||
|
||||
@ -39,6 +56,16 @@ public abstract class GenericEnumType<T, E extends Enum<E>> implements UserType,
|
||||
this.sqlType = sqlType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
|
||||
return nullSafeGet(rs, names, owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
|
||||
nullSafeSet(st, value, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object assemble(Serializable cached, Object owner) {
|
||||
return cached;
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.faces.application.FacesMessage;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface UIMessage extends Serializable {
|
||||
|
||||
String getDetail();
|
||||
|
||||
String getMessage();
|
||||
|
||||
UIMessageType getMessageType();
|
||||
|
||||
FacesMessage getFacesMessage();
|
||||
|
||||
FacesMessage getFacesMessage(String prefix);
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public enum UIMessageType {
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR;
|
||||
|
||||
}
|
||||
@ -1,84 +1,87 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil.jwt;
|
||||
|
||||
import io.fusionauth.jwt.Verifier;
|
||||
import io.fusionauth.jwt.domain.JWT;
|
||||
import io.fusionauth.jwt.hmac.HMACVerifier;
|
||||
import java.time.ZonedDateTime;
|
||||
import org.primeframework.jwt.Verifier;
|
||||
import org.primeframework.jwt.domain.JWT;
|
||||
import org.primeframework.jwt.domain.JWTException;
|
||||
import org.primeframework.jwt.hmac.HMACVerifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class JWTDecoder {
|
||||
|
||||
private boolean parsedSuccessfully = false;
|
||||
private JWT jwt = null;
|
||||
private boolean parsedSuccessfully;
|
||||
private JWT jwt = null;
|
||||
|
||||
public JWTDecoder(String password, String issuer, String jwtString) throws JWTException {
|
||||
if ((password == null) || (issuer == null) || (jwtString == null)) {
|
||||
throw new JWTException("password, issuer and jwt must not be null");
|
||||
}
|
||||
Verifier verifier = HMACVerifier.newVerifier(password);
|
||||
// Verifier verifier = RSAVerifier.newVerifier(new String(Files.readAllBytes(Paths.get("public_key.pem"))));
|
||||
try {
|
||||
jwt = JWT.getDecoder().decode(jwtString, verifier);
|
||||
parsedSuccessfully = jwt.issuer.equals(issuer);
|
||||
} catch (JWTException ex) {
|
||||
jwt = null;
|
||||
}
|
||||
public JWTDecoder(String password, String issuer, String jwtString) throws JWTException {
|
||||
if ((password == null) || (issuer == null) || (jwtString == null)) {
|
||||
throw new JWTException("password, issuer and jwt must not be null");
|
||||
}
|
||||
Verifier verifier = HMACVerifier.newVerifier(password);
|
||||
jwt = JWT.getDecoder().decode(jwtString, verifier);
|
||||
parsedSuccessfully = jwt != null && jwt.issuer.equals(issuer);
|
||||
}
|
||||
|
||||
public String getIssuer() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.issuer;
|
||||
}
|
||||
public String getIssuer() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.issuer;
|
||||
}
|
||||
}
|
||||
|
||||
public ZonedDateTime getIssuedAt() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.issuedAt;
|
||||
}
|
||||
public ZonedDateTime getIssuedAt() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.issuedAt;
|
||||
}
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.subject;
|
||||
}
|
||||
public String getSubject() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.subject;
|
||||
}
|
||||
}
|
||||
|
||||
public String getUniqueId() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.uniqueId;
|
||||
}
|
||||
public String getUniqueId() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.uniqueId;
|
||||
}
|
||||
}
|
||||
|
||||
public ZonedDateTime getExpiration() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.expiration;
|
||||
}
|
||||
public ZonedDateTime getExpiration() {
|
||||
if (jwt == null) {
|
||||
return null;
|
||||
} else {
|
||||
return jwt.expiration;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
if ((jwt == null) || (jwt.isExpired())) {
|
||||
return false;
|
||||
} else {
|
||||
return this.parsedSuccessfully;
|
||||
}
|
||||
public boolean isValid() {
|
||||
if ((jwt == null) || (jwt.isExpired())) {
|
||||
return false;
|
||||
} else {
|
||||
return this.parsedSuccessfully;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,28 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil.jwt;
|
||||
|
||||
import io.fusionauth.jwt.Signer;
|
||||
import io.fusionauth.jwt.domain.JWT;
|
||||
import io.fusionauth.jwt.hmac.HMACSigner;
|
||||
import java.time.ZonedDateTime;
|
||||
import org.primeframework.jwt.Signer;
|
||||
import org.primeframework.jwt.domain.JWT;
|
||||
import org.primeframework.jwt.hmac.HMACSigner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public abstract class JWTEncoder {
|
||||
|
||||
|
||||
@ -1,14 +1,23 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package de.muehlencord.shared.jeeutil.jwt;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class JWTException extends Exception {
|
||||
|
||||
|
||||
@ -1,7 +1,17 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package de.muehlencord.shared.jeeutil.jwt;
|
||||
|
||||
@ -12,7 +22,7 @@ import org.apache.shiro.web.filter.authc.AuthenticationFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class JWTGuard extends AuthenticationFilter {
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 jomu.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -19,7 +19,7 @@ import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public interface APIError {
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 jomu.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -26,7 +26,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@ -60,14 +60,14 @@ public class APIErrorResponse {
|
||||
this.rootCause = rootCauseMessage;
|
||||
}
|
||||
|
||||
public APIErrorResponse(Exception exception, Locale locale) {
|
||||
public APIErrorResponse(Exception exception) {
|
||||
this.status = Response.Status.INTERNAL_SERVER_ERROR;
|
||||
this.errorCode = "0";
|
||||
this.message = exception.getLocalizedMessage();
|
||||
this.rootCause = null;
|
||||
}
|
||||
|
||||
public APIErrorResponse(Exception exception, Locale locale, Throwable th) {
|
||||
public APIErrorResponse(Exception exception, Throwable th) {
|
||||
this.status = Response.Status.INTERNAL_SERVER_ERROR;
|
||||
this.errorCode = "0";
|
||||
this.message = exception.getLocalizedMessage();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 jomu.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -22,7 +22,7 @@ import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class APIException extends RuntimeException {
|
||||
|
||||
@ -31,7 +31,7 @@ public class APIException extends RuntimeException {
|
||||
public static final String HTTP_HEADER_X_ROOT_CAUSE = "X-Root-Cause";
|
||||
private static final long serialVersionUID = -4356132354448841938L;
|
||||
|
||||
private final Response httpResponse;
|
||||
private final transient Response httpResponse;
|
||||
|
||||
public APIException(APIError apiError, Locale locale) {
|
||||
httpResponse = createHttpResponse(new APIErrorResponse(apiError, locale));
|
||||
@ -45,8 +45,12 @@ public class APIException extends RuntimeException {
|
||||
httpResponse = createHttpResponse(new APIErrorResponse(apiError, locale, rootCause));
|
||||
}
|
||||
|
||||
public APIException(Exception exception, Locale locale) {
|
||||
httpResponse = createHttpResponse(new APIErrorResponse(exception, locale));
|
||||
public APIException(APIError apiError, String locale, String rootCause) {
|
||||
httpResponse = createHttpResponse(new APIErrorResponse(apiError, new Locale(locale), rootCause));
|
||||
}
|
||||
|
||||
public APIException(Exception exception) {
|
||||
httpResponse = createHttpResponse(new APIErrorResponse(exception));
|
||||
}
|
||||
|
||||
public Response getHttpResponse() {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 joern (at) muehlencord.de
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -21,41 +21,45 @@ import javax.interceptor.AroundInvoke;
|
||||
import javax.interceptor.InvocationContext;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
public class APIExceptionInterceptor {
|
||||
|
||||
@Inject
|
||||
Locale locale;
|
||||
private static final Logger logger = LoggerFactory.getLogger(APIExceptionInterceptor.class);
|
||||
|
||||
@AroundInvoke
|
||||
public Object handleException(InvocationContext context) {
|
||||
Object proceedResponse;
|
||||
try {
|
||||
// continue to execute context
|
||||
// if an exception is thrown during processing, this is passed in to the catch block below
|
||||
proceedResponse = context.proceed();
|
||||
} catch (Exception ex) {
|
||||
Response errorResponse;
|
||||
if (ex instanceof APIException) {
|
||||
errorResponse = ((APIException) ex).getHttpResponse();
|
||||
} else if (ex.getCause() instanceof APIException) {
|
||||
errorResponse = ((APIException) ex.getCause()).getHttpResponse();
|
||||
} else if (ex instanceof ConstraintViolationException) {
|
||||
// this exception is handled via the ConstraintViolationMapper
|
||||
throw (ConstraintViolationException) ex;
|
||||
} else if (ex.getCause() instanceof ConstraintViolationException) {
|
||||
// this exception is handled via the ConstraintViolationMapper
|
||||
throw (ConstraintViolationException) ex.getCause();
|
||||
} else {
|
||||
errorResponse = new APIException(ex, locale).getHttpResponse();
|
||||
}
|
||||
return errorResponse;
|
||||
}
|
||||
return proceedResponse;
|
||||
@Inject
|
||||
Locale locale;
|
||||
|
||||
@AroundInvoke
|
||||
public Object handleException(InvocationContext context) {
|
||||
Object proceedResponse;
|
||||
try {
|
||||
// continue to execute context
|
||||
// if an exception is thrown during processing, this is passed in to the catch block below
|
||||
proceedResponse = context.proceed();
|
||||
} catch (Exception ex) {
|
||||
logger.debug(ex.getMessage(), ex);
|
||||
Response errorResponse;
|
||||
if (ex instanceof APIException) {
|
||||
errorResponse = ((APIException) ex).getHttpResponse();
|
||||
} else if (ex.getCause() instanceof APIException) {
|
||||
errorResponse = ((APIException) ex.getCause()).getHttpResponse();
|
||||
} else if (ex instanceof ConstraintViolationException) {
|
||||
// this exception is handled via the ConstraintViolationMapper
|
||||
throw (ConstraintViolationException) ex;
|
||||
} else if (ex.getCause() instanceof ConstraintViolationException) {
|
||||
// this exception is handled via the ConstraintViolationMapper
|
||||
throw (ConstraintViolationException) ex.getCause();
|
||||
} else {
|
||||
errorResponse = new APIException(ex).getHttpResponse();
|
||||
}
|
||||
return errorResponse;
|
||||
}
|
||||
return proceedResponse;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 joern (at) muehlencord.de
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -22,7 +22,7 @@ import javax.ws.rs.ext.Provider;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord (joern (at) muehlencord.de
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@Provider
|
||||
public class BadRequestMapper implements ExceptionMapper<BadRequestException> {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 jomu.
|
||||
* Copyright 2019 Joern Muehlencord (joern@muehlencord.de).
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -24,7 +24,7 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jomu
|
||||
* @author Joern Muehlencord (joern@muehlencord.de)
|
||||
*/
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user