initial import

This commit is contained in:
2026-05-11 19:59:10 +07:00
commit 582353e277
479 changed files with 32418 additions and 0 deletions

View File

@ -0,0 +1,17 @@
-- begin TMSEXT_FOO
create table TMSEXT_FOO (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
NAME varchar(255) not null,
AGE integer not null,
--
primary key (ID)
)^
-- end TMSEXT_FOO

View File

@ -0,0 +1,18 @@
-- begin PSWDPLUS_PASSWORD_HISTORY
create table PSWDPLUS_PASSWORD_HISTORY (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
USER_ID uuid,
CREATED_AT timestamp,
PASSWORD_HASH varchar(255),
--
primary key (ID)
)^
-- end PSWDPLUS_PASSWORD_HISTORY

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,5 @@
-- begin PSWDPLUS_PASSWORD_HISTORY
alter table PSWDPLUS_PASSWORD_HISTORY add constraint FK_PSWDPLUS_PASSWORD_HISTORY_ON_USER foreign key (USER_ID) references SEC_USER(ID)^
create index IDX_PSWDPLUS_PASSWORD_HISTORY_ON_USER on PSWDPLUS_PASSWORD_HISTORY (USER_ID)^
-- end PSWDPLUS_PASSWORD_HISTORY

View File

@ -0,0 +1,605 @@
-- begin TMS_HEART_BEAT
create table TMS_HEART_BEAT (
ID uuid,
CREATE_TS timestamp,
CREATED_BY varchar(50),
VERSION integer not null,
--
TERMINAL_ID uuid not null,
BATTERY_TEMP double precision not null,
BATTERY_PERCENTAGE integer not null,
LATITUDE double precision,
LONGITUDE double precision,
CELL_INFOS varchar(500),
CELL_NAME varchar(50),
CELL_TYPE varchar(10),
CELL_STRENGTH integer,
--
primary key (ID)
)^
-- end TMS_HEART_BEAT
-- begin TMS_DELETE_TASK_LOG
create table TMS_DELETE_TASK_LOG (
ID uuid,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
VERSION integer not null,
--
TASK_ID uuid not null,
APPLICATION_SIMPLE_ID uuid not null,
TERMINAL_ID uuid not null,
ACTIVITY integer not null,
OLD_ACTIVITY integer,
LAST_BROADCAST_TS timestamp,
MESSAGE varchar(255),
--
primary key (ID)
)^
-- end TMS_DELETE_TASK_LOG
-- begin TMS_CONTACT_PERSON
create table TMS_CONTACT_PERSON (
ID uuid,
VERSION integer not null,
--
NAME varchar(100) not null,
PHONE varchar(100),
MOBILE varchar(100) not null,
EMAIL varchar(255) not null,
MERCHANT_ID uuid,
--
primary key (ID)
)^
-- end TMS_CONTACT_PERSON
-- begin TMS_APPLICATION_SIMPLE
create table TMS_APPLICATION_SIMPLE (
ID uuid,
--
APP_NAME varchar(255) not null,
PACKAGE_NAME varchar(255) not null,
APP_VERSION varchar(50) not null,
DIAGNOSTIC_INFO_ID uuid,
--
primary key (ID)
)^
-- end TMS_APPLICATION_SIMPLE
-- begin TMS_DOWNLOAD_TASK_LOG
create table TMS_DOWNLOAD_TASK_LOG (
ID uuid,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
VERSION integer not null,
--
TASK_ID uuid not null,
APPLICATION_ID uuid not null,
TERMINAL_ID uuid not null,
ACTIVITY integer not null,
OLD_ACTIVITY integer,
LAST_BROADCAST_TS timestamp,
MESSAGE varchar(255),
--
primary key (ID)
)^
-- end TMS_DOWNLOAD_TASK_LOG
-- begin TMS_DIAGNOSTIC_INFO
create table TMS_DIAGNOSTIC_INFO (
ID uuid,
TERMINAL_ID uuid not null,
BATTERY_TEMP double precision not null,
BATTERY_PERCENTAGE integer not null,
LATITUDE double precision,
LONGITUDE double precision,
CREATE_TS timestamp,
CREATED_BY varchar(50),
VERSION integer not null,
CELL_INFOS varchar(500),
CELL_NAME varchar(50),
CELL_TYPE varchar(10),
CELL_STRENGTH integer,
--
MEID varchar(20),
INSTALLED_APPS_STRING text,
TOTAL_MEMORY bigint,
AVAILABLE_MEMORY bigint,
TOTAL_FLASH_MEMORY bigint,
AVAILABLE_FLASH_MEMORY bigint,
TOTAL_MOBILE_DATA bigint,
SWITCHING_TIMES integer,
CURRENT_BOOT_TIME integer,
TOTAL_BOOT_TIME integer,
TOTAL_LENGTH_PRINTED double precision,
SWIPING_CARD_TIMES integer,
DIP_INSERTING_TIMES integer,
NFC_CARD_READING_TIMES integer,
FRONT_CAMERA_OPEN_TIMES integer,
REAR_CAMERA_OPEN_TIMES integer,
SAM_AVAILABLE boolean,
CHARGE_TIMES integer,
--
primary key (ID)
)^
-- end TMS_DIAGNOSTIC_INFO
-- begin TMS_CITY
create table TMS_CITY (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
STATES_ID uuid not null,
NAME varchar(50) not null,
--
primary key (ID)
)^
-- end TMS_CITY
-- begin TMS_COUNTRY
create table TMS_COUNTRY (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
CODE varchar(2) not null,
NAME varchar(50) not null,
--
primary key (ID)
)^
-- end TMS_COUNTRY
-- begin TMS_TERMINAL_LINK
create table TMS_TERMINAL_LINK (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
--
TERMINAL_ID uuid not null,
TERMINAL_EXT_ID uuid not null,
--
primary key (ID)
)^
-- end TMS_TERMINAL_LINK
-- begin TMS_TERMINAL_GROUP
create table TMS_TERMINAL_GROUP (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
NAME varchar(100) not null,
DESCRIPTION varchar(255),
--
primary key (ID)
)^
-- end TMS_TERMINAL_GROUP
-- begin TMS_STATES
create table TMS_STATES (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
COUNTRY_ID uuid not null,
NAME varchar(50) not null,
--
primary key (ID)
)^
-- end TMS_STATES
-- begin TMS_DEVICE_MODEL
create table TMS_DEVICE_MODEL (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
MODEL varchar(50) not null,
MODEL_INFORMATION text,
VENDOR_NAME varchar(100) not null,
VENDOR_COUNTRY varchar(50) not null,
--
primary key (ID)
)^
-- end TMS_DEVICE_MODEL
-- begin TMS_MERCHANT_TYPE
create table TMS_MERCHANT_TYPE (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
NAME varchar(100) not null,
DESCRIPTION varchar(255),
--
primary key (ID)
)^
-- end TMS_MERCHANT_TYPE
-- begin TMS_DISTRICT
create table TMS_DISTRICT (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
CITY_ID uuid not null,
NAME varchar(50) not null,
--
primary key (ID)
)^
-- end TMS_DISTRICT
-- begin TMS_APPLICATION
create table TMS_APPLICATION (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
TENANT_ID varchar(255),
--
PACKAGE_NAME varchar(255) not null,
COMPANY_NAME varchar(100) not null,
NAME varchar(100) not null,
DESCRIPTION varchar(255),
APP_VERSION varchar(50) not null,
ICON_ID uuid,
APK_ID uuid not null,
UNINSTALLABLE boolean,
DOWNLOAD_URL varchar(500),
CHECKSUM varchar(32),
--
primary key (ID)
)^
-- end TMS_APPLICATION
-- begin TMS_MERCHANT
create table TMS_MERCHANT (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
TENANT_ID varchar(255),
--
NAME varchar(100) not null,
TYPE_ID uuid not null,
COMPANY_NAME varchar(100) not null,
DISTRICT_ID uuid not null,
ADDRESS varchar(255) not null,
ZIPCODE varchar(5) not null,
--
primary key (ID)
)^
-- end TMS_MERCHANT
-- begin TMS_DEVICE_PROFILE
create table TMS_DEVICE_PROFILE (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
TENANT_ID varchar(255),
--
NAME varchar(50) not null,
HEARTBEAT_INTERVAL integer not null,
DIAGNOSTIC_INTERVAL integer not null,
MASK_HOME_BUTTON boolean not null,
MASK_STATUS_BAR boolean not null,
SCHEDULE_REBOOT boolean not null,
SCHEDULE_REBOOT_TIME time,
RELOCATION_ALERT boolean,
MOVING_THRESHOLD integer,
ADMIN_PASSWORD varchar(8),
IS_DEFAULT boolean,
FRONT_APP varchar(255),
HOST_REPORT boolean,
HOST_REPORT_TIMEOUT integer,
HOST_REPORT_URL varchar(255),
HOST_REPORT_API_KEY varchar(64),
HOST_LOGGING boolean,
HOST_LOGGING_TIMEOUT integer,
HOST_LOGGING_URL varchar(255),
HOST_LOGGING_API_KEY varchar(64),
HOST_LOGGING_INTERVAL integer,
--
primary key (ID)
)^
-- end TMS_DEVICE_PROFILE
-- begin TMS_DELETE_TASK
create table TMS_DELETE_TASK (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
TENANT_ID varchar(255),
--
NAME varchar(50) not null,
STATUS integer not null,
DELETE_TIME timestamp,
--
primary key (ID)
)^
-- end TMS_DELETE_TASK
-- begin TMS_DOWNLOAD_TASK
create table TMS_DOWNLOAD_TASK (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
TENANT_ID varchar(255),
--
NAME varchar(50) not null,
STATUS integer not null,
DOWNLOAD_TIME_TYPE integer not null,
DOWNLOAD_TIME timestamp,
INSTALLATION_TIME_TYPE integer not null,
INSTALLATION_TIME timestamp,
INSTALLATION_NOTIFICATION integer not null,
--
primary key (ID)
)^
-- end TMS_DOWNLOAD_TASK
-- begin TMS_TERMINAL
create table TMS_TERMINAL (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
TENANT_ID varchar(255),
--
SN varchar(30) not null,
IMEI varchar(25) not null,
MODEL_ID uuid not null,
MERCHANT_ID uuid not null,
PROFILE_ID uuid,
IMPORT_DEFAULT boolean,
HEARTBEAT_STATUS integer,
LAST_HEARTBEAT_TIME timestamp,
LAST_HEARTBEAT_ID uuid,
LAST_INIT_TIME timestamp,
LAST_INIT_AID_TIME timestamp,
LAST_INIT_CAPK_TIME timestamp,
LAST_INIT_CONTACTLESS_AID_TIME timestamp,
LAST_INIT_CARDS_TIME timestamp,
LAST_INIT_TERMINAL_TIME timestamp,
LATITUDE double precision,
LONGITUDE double precision,
LAST_DIAGNOSTIC_TIME timestamp,
LAST_DIAGNOSTIC_ID uuid,
APP_VERSION varchar(50),
LAUNCHER_VERSION varchar(50),
VFS_VERSION varchar(50),
VFSS_VERSION varchar(50),
CELL_NAME varchar(255),
--
primary key (ID)
)^
-- end TMS_TERMINAL
-- begin TMS_DOWNLOAD_TASK_TERMINAL_LINK
create table TMS_DOWNLOAD_TASK_TERMINAL_LINK (
TERMINAL_ID uuid,
DOWNLOAD_TASK_ID uuid,
primary key (TERMINAL_ID, DOWNLOAD_TASK_ID)
)^
-- end TMS_DOWNLOAD_TASK_TERMINAL_LINK
-- begin TMS_DOWNLOAD_TASK_APPLICATION_LINK
create table TMS_DOWNLOAD_TASK_APPLICATION_LINK (
DOWNLOAD_TASK_ID uuid,
APPLICATION_ID uuid,
primary key (DOWNLOAD_TASK_ID, APPLICATION_ID)
)^
-- end TMS_DOWNLOAD_TASK_APPLICATION_LINK
-- begin TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK
create table TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK (
DOWNLOAD_TASK_ID uuid,
GROUP_ID uuid,
primary key (DOWNLOAD_TASK_ID, GROUP_ID)
)^
-- end TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK
-- begin TMS_TERMINAL_GROUP_LINK
create table TMS_TERMINAL_GROUP_LINK (
TERMINAL_ID uuid,
TERMINAL_GROUP_ID uuid,
primary key (TERMINAL_ID, TERMINAL_GROUP_ID)
)^
-- end TMS_TERMINAL_GROUP_LINK
-- begin TMS_DELETE_TASK_APPLICATION_LINK
create table TMS_DELETE_TASK_APPLICATION_LINK (
APPLICATION_ID uuid,
DELETE_TASK_ID uuid,
primary key (APPLICATION_ID, DELETE_TASK_ID)
)^
-- end TMS_DELETE_TASK_APPLICATION_LINK
-- begin TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK
create table TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK (
DELETE_TASK_ID uuid,
APPLICATION_SIMPLE_ID uuid,
primary key (DELETE_TASK_ID, APPLICATION_SIMPLE_ID)
)^
-- end TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK
-- begin TMS_DELETE_TASK_TERMINAL_GROUP_LINK
create table TMS_DELETE_TASK_TERMINAL_GROUP_LINK (
DELETE_TASK_ID uuid,
GROUP_ID uuid,
primary key (DELETE_TASK_ID, GROUP_ID)
)^
-- end TMS_DELETE_TASK_TERMINAL_GROUP_LINK
-- begin TMS_DEVICE_PROFILE_ACQUIRER_LINK
create table TMS_DEVICE_PROFILE_ACQUIRER_LINK (
DEVICE_PROFILE_ID uuid,
ACQUIRER_ID uuid,
primary key (DEVICE_PROFILE_ID, ACQUIRER_ID)
)^
-- end TMS_DEVICE_PROFILE_ACQUIRER_LINK
-- begin TMS_TERMINAL_LAST_UPDATE
create table TMS_TERMINAL_LAST_UPDATE (
ID uuid,
CREATE_TS timestamp,
CREATED_BY varchar(50),
--
SN varchar(255),
HAS_UPDATE boolean,
FORCE_UPDATE boolean,
LAST_INIT_TIME timestamp,
--
primary key (ID)
)^
-- end TMS_TERMINAL_LAST_UPDATE
-- begin TMS_TERMINAL_LAST_STEP_UPDATE
create table TMS_TERMINAL_LAST_STEP_UPDATE (
ID uuid,
CREATE_TS timestamp,
CREATED_BY varchar(50),
--
SN varchar(255),
STEP_NAME varchar(255),
LAST_INIT_TIME timestamp,
--
primary key (ID)
)^
-- end TMS_TERMINAL_LAST_STEP_UPDATE
-- begin TMS_TERMINAL_ACK_UPDATE
create table TMS_TERMINAL_ACK_UPDATE (
ID uuid,
CREATE_TS timestamp,
CREATED_BY varchar(50),
--
SN varchar(255),
LAST_INIT_TIME timestamp,
SYNC_START_TIME timestamp,
SYNC_END_TIME timestamp,
RETRY_COUNT integer,
--
primary key (ID)
)^
-- end TMS_TERMINAL_ACK_UPDATE
-- begin TMS_RESPONSE_CODE
create table TMS_RESPONSE_CODE (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
UPDATE_TS timestamp,
UPDATED_BY varchar(50),
DELETE_TS timestamp,
DELETED_BY varchar(50),
--
TYPE varchar(50) not null,
CODE varchar(2) not null,
DESCRIPTION varchar(255) not null,
--
primary key (ID)
)^
-- end TMS_RESPONSE_CODE
-- begin TMS_DEVICE_PROFILE_APP
create table TMS_DEVICE_PROFILE_APP (
ID uuid,
--
PACKAGE_NAME varchar(255) not null,
PROFILE_ID uuid not null,
--
primary key (ID)
)^
-- end TMS_DEVICE_PROFILE_APP
-- begin TMS_TERMINAL_PROFILING
create table TMS_TERMINAL_PROFILING (
ID uuid,
VERSION integer not null,
CREATE_TS timestamp,
CREATED_BY varchar(50),
--
FILE uuid,
--
primary key (ID)
)^
-- end TMS_TERMINAL_PROFILING
-- begin TMS_TERMINAL_PROFILING_ITEMS
create table TMS_TERMINAL_PROFILING_ITEMS (
ID uuid,
CREATE_TS timestamp,
CREATED_BY varchar(50),
--
PROFILING_ID uuid,
sn varchar(30) not null,
imei varchar(25) not null,
model_name varchar(50) not null,
merchant_name varchar(100) not null,
profile_name varchar(50) not null,
group_names varchar(255) not null,
terminal_id_template varchar(8) not null,
terminal_id varchar(8) not null,
merchant_id varchar(15) not null,
merchant_name1 varchar(30) not null,
merchant_name2 varchar(30),
merchant_name3 varchar(30),
merchant_name4 varchar(30),
merchant_name5 varchar(30),
--
primary key (ID)
)^
-- end TMS_TERMINAL_PROFILING_ITEMS
-- begin TMS_TERMINAL_GROUP_IMPORT_STAGE
create table TMS_TERMINAL_GROUP_IMPORT_STAGE (
IMPORT_ID uuid not null,
ROW_NO integer not null,
CREATE_TS timestamp default current_timestamp,
--
TID varchar(255),
SN varchar(255),
TID_NORM varchar(255),
SN_NORM varchar(255),
SN_LOWER_NORM varchar(255),
--
primary key (IMPORT_ID, ROW_NO)
)^
-- end TMS_TERMINAL_GROUP_IMPORT_STAGE

View File

@ -0,0 +1,126 @@
-- begin TMS_HEART_BEAT
alter table TMS_HEART_BEAT add constraint FK_TMS_HEART_BEAT_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID)^
create index IDX_TMS_HEART_BEAT_ON_TERMINAL on TMS_HEART_BEAT (TERMINAL_ID)^
-- end TMS_HEART_BEAT
-- begin TMS_DELETE_TASK_LOG
alter table TMS_DELETE_TASK_LOG add constraint FK_TMS_DELETE_TASK_LOG_ON_TASK foreign key (TASK_ID) references TMS_DELETE_TASK(ID)^
alter table TMS_DELETE_TASK_LOG add constraint FK_TMS_DELETE_TASK_LOG_ON_APPLICATION_SIMPLE foreign key (APPLICATION_SIMPLE_ID) references TMS_APPLICATION_SIMPLE(ID) on delete CASCADE^
alter table TMS_DELETE_TASK_LOG add constraint FK_TMS_DELETE_TASK_LOG_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID)^
create index IDX_TMS_DELETE_TASK_LOG_ON_TASK on TMS_DELETE_TASK_LOG (TASK_ID)^
create index IDX_TMS_DELETE_TASK_LOG_ON_APPLICATION_SIMPLE on TMS_DELETE_TASK_LOG (APPLICATION_SIMPLE_ID)^
create index IDX_TMS_DELETE_TASK_LOG_ON_TERMINAL on TMS_DELETE_TASK_LOG (TERMINAL_ID)^
-- end TMS_DELETE_TASK_LOG
-- begin TMS_CONTACT_PERSON
alter table TMS_CONTACT_PERSON add constraint FK_TMS_CONTACT_PERSON_ON_MERCHANT foreign key (MERCHANT_ID) references TMS_MERCHANT(ID)^
create index IDX_TMS_CONTACT_PERSON_ON_MERCHANT on TMS_CONTACT_PERSON (MERCHANT_ID)^
-- end TMS_CONTACT_PERSON
-- begin TMS_APPLICATION_SIMPLE
alter table TMS_APPLICATION_SIMPLE add constraint FK_TMS_APPLICATION_SIMPLE_ON_DIAGNOSTIC_INFO foreign key (DIAGNOSTIC_INFO_ID) references TMS_DIAGNOSTIC_INFO(ID)^
create index IDX_TMS_APPLICATION_SIMPLE_ON_DIAGNOSTIC_INFO on TMS_APPLICATION_SIMPLE (DIAGNOSTIC_INFO_ID)^
-- end TMS_APPLICATION_SIMPLE
-- begin TMS_DOWNLOAD_TASK_LOG
alter table TMS_DOWNLOAD_TASK_LOG add constraint FK_TMS_DOWNLOAD_TASK_LOG_ON_TASK foreign key (TASK_ID) references TMS_DOWNLOAD_TASK(ID)^
alter table TMS_DOWNLOAD_TASK_LOG add constraint FK_TMS_DOWNLOAD_TASK_LOG_ON_APPLICATION foreign key (APPLICATION_ID) references TMS_APPLICATION(ID)^
alter table TMS_DOWNLOAD_TASK_LOG add constraint FK_TMS_DOWNLOAD_TASK_LOG_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID)^
create index IDX_TMS_DOWNLOAD_TASK_LOG_ON_TASK on TMS_DOWNLOAD_TASK_LOG (TASK_ID)^
create index IDX_TMS_DOWNLOAD_TASK_LOG_ON_APPLICATION on TMS_DOWNLOAD_TASK_LOG (APPLICATION_ID)^
create index IDX_TMS_DOWNLOAD_TASK_LOG_ON_TERMINAL on TMS_DOWNLOAD_TASK_LOG (TERMINAL_ID)^
-- end TMS_DOWNLOAD_TASK_LOG
-- begin TMS_DIAGNOSTIC_INFO
alter table TMS_DIAGNOSTIC_INFO add constraint FK_TMS_DIAGNOSTIC_INFO_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID)^
create index IDX_TMS_DIAGNOSTIC_INFO_ON_TERMINAL on TMS_DIAGNOSTIC_INFO (TERMINAL_ID)^
-- end TMS_DIAGNOSTIC_INFO
-- begin TMS_CITY
alter table TMS_CITY add constraint FK_TMS_CITY_ON_STATES foreign key (STATES_ID) references TMS_STATES(ID)^
create index IDX_TMS_CITY_ON_STATES on TMS_CITY (STATES_ID)^
-- end TMS_CITY
-- begin TMS_COUNTRY
create unique index IDX_TMS_COUNTRY_UK_CODE on TMS_COUNTRY (CODE) where DELETE_TS is null ^
-- end TMS_COUNTRY
-- begin TMS_TERMINAL_LINK
alter table TMS_TERMINAL_LINK add constraint FK_TMS_TERMINAL_LINK_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID)^
alter table TMS_TERMINAL_LINK add constraint FK_TMS_TERMINAL_LINK_ON_TERMINAL_EXT foreign key (TERMINAL_EXT_ID) references TMSEXT_TERMINAL_EXT(ID)^
create index IDX_TMS_TERMINAL_LINK_ON_TERMINAL on TMS_TERMINAL_LINK (TERMINAL_ID)^
create index IDX_TMS_TERMINAL_LINK_ON_TERMINAL_EXT on TMS_TERMINAL_LINK (TERMINAL_EXT_ID)^
-- end TMS_TERMINAL_LINK
-- begin TMS_STATES
alter table TMS_STATES add constraint FK_TMS_STATES_ON_COUNTRY foreign key (COUNTRY_ID) references TMS_COUNTRY(ID)^
create index IDX_TMS_STATES_ON_COUNTRY on TMS_STATES (COUNTRY_ID)^
-- end TMS_STATES
-- begin TMS_DISTRICT
alter table TMS_DISTRICT add constraint FK_TMS_DISTRICT_ON_CITY foreign key (CITY_ID) references TMS_CITY(ID)^
create index IDX_TMS_DISTRICT_ON_CITY on TMS_DISTRICT (CITY_ID)^
-- end TMS_DISTRICT
-- begin TMS_APPLICATION
alter table TMS_APPLICATION add constraint FK_TMS_APPLICATION_ON_ICON foreign key (ICON_ID) references SYS_FILE(ID)^
alter table TMS_APPLICATION add constraint FK_TMS_APPLICATION_ON_APK foreign key (APK_ID) references SYS_FILE(ID)^
create unique index IDX_TMS_APPLICATION_UNQ on TMS_APPLICATION (PACKAGE_NAME, VERSION) where DELETE_TS is null ^
create index IDX_TMS_APPLICATION_ON_ICON on TMS_APPLICATION (ICON_ID)^
create index IDX_TMS_APPLICATION_ON_APK on TMS_APPLICATION (APK_ID)^
-- end TMS_APPLICATION
-- begin TMS_MERCHANT
alter table TMS_MERCHANT add constraint FK_TMS_MERCHANT_ON_TYPE foreign key (TYPE_ID) references TMS_MERCHANT_TYPE(ID)^
alter table TMS_MERCHANT add constraint FK_TMS_MERCHANT_ON_DISTRICT foreign key (DISTRICT_ID) references TMS_DISTRICT(ID)^
create index IDX_TMS_MERCHANT_ON_TYPE on TMS_MERCHANT (TYPE_ID)^
create index IDX_TMS_MERCHANT_ON_DISTRICT on TMS_MERCHANT (DISTRICT_ID)^
-- end TMS_MERCHANT
-- begin TMS_TERMINAL
alter table TMS_TERMINAL add constraint FK_TMS_TERMINAL_ON_MODEL foreign key (MODEL_ID) references TMS_DEVICE_MODEL(ID)^
alter table TMS_TERMINAL add constraint FK_TMS_TERMINAL_ON_MERCHANT foreign key (MERCHANT_ID) references TMS_MERCHANT(ID)^
alter table TMS_TERMINAL add constraint FK_TMS_TERMINAL_ON_PROFILE foreign key (PROFILE_ID) references TMS_DEVICE_PROFILE(ID)^
create unique index IDX_TMS_TERMINAL_UK_IMEI on TMS_TERMINAL (IMEI) where DELETE_TS is null ^
create unique index IDX_TMS_TERMINAL_UK_SN on TMS_TERMINAL (SN) where DELETE_TS is null ^
create unique index IDX_TMS_TERMINAL_UNQ on TMS_TERMINAL (SN, IMEI) where DELETE_TS is null ^
create index IDX_TMS_TERMINAL_ON_MODEL on TMS_TERMINAL (MODEL_ID)^
create index IDX_TMS_TERMINAL_ON_MERCHANT on TMS_TERMINAL (MERCHANT_ID)^
create index IDX_TMS_TERMINAL_ON_PROFILE on TMS_TERMINAL (PROFILE_ID)^
-- end TMS_TERMINAL
-- begin TMS_DOWNLOAD_TASK_TERMINAL_LINK
alter table TMS_DOWNLOAD_TASK_TERMINAL_LINK add constraint FK_DOWTASTER_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID)^
alter table TMS_DOWNLOAD_TASK_TERMINAL_LINK add constraint FK_DOWTASTER_ON_DOWNLOAD_TASK foreign key (DOWNLOAD_TASK_ID) references TMS_DOWNLOAD_TASK(ID)^
-- end TMS_DOWNLOAD_TASK_TERMINAL_LINK
-- begin TMS_DOWNLOAD_TASK_APPLICATION_LINK
alter table TMS_DOWNLOAD_TASK_APPLICATION_LINK add constraint FK_DOWTASAPP_ON_DOWNLOAD_TASK foreign key (DOWNLOAD_TASK_ID) references TMS_DOWNLOAD_TASK(ID)^
alter table TMS_DOWNLOAD_TASK_APPLICATION_LINK add constraint FK_DOWTASAPP_ON_APPLICATION foreign key (APPLICATION_ID) references TMS_APPLICATION(ID)^
-- end TMS_DOWNLOAD_TASK_APPLICATION_LINK
-- begin TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK
alter table TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK add constraint FK_DOWTASTERGRO_ON_DOWNLOAD_TASK foreign key (DOWNLOAD_TASK_ID) references TMS_DOWNLOAD_TASK(ID)^
alter table TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK add constraint FK_DOWTASTERGRO_ON_TERMINAL_GROUP foreign key (GROUP_ID) references TMS_TERMINAL_GROUP(ID)^
-- end TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK
-- begin TMS_TERMINAL_GROUP_LINK
alter table TMS_TERMINAL_GROUP_LINK add constraint FK_TERGRO_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID)^
alter table TMS_TERMINAL_GROUP_LINK add constraint FK_TERGRO_ON_TERMINAL_GROUP foreign key (TERMINAL_GROUP_ID) references TMS_TERMINAL_GROUP(ID)^
-- end TMS_TERMINAL_GROUP_LINK
-- begin TMS_DELETE_TASK_APPLICATION_LINK
alter table TMS_DELETE_TASK_APPLICATION_LINK add constraint FK_DELTASAPP_ON_APPLICATION_SIMPLE foreign key (APPLICATION_ID) references TMS_APPLICATION_SIMPLE(ID)^
alter table TMS_DELETE_TASK_APPLICATION_LINK add constraint FK_DELTASAPP_ON_DELETE_TASK foreign key (DELETE_TASK_ID) references TMS_DELETE_TASK(ID)^
-- end TMS_DELETE_TASK_APPLICATION_LINK
-- begin TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK
alter table TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK add constraint FK_DELTASAPPSIM_ON_DELETE_TASK foreign key (DELETE_TASK_ID) references TMS_DELETE_TASK(ID)^
alter table TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK add constraint FK_DELTASAPPSIM_ON_APPLICATION_SIMPLE foreign key (APPLICATION_SIMPLE_ID) references TMS_APPLICATION_SIMPLE(ID)^
-- end TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK
-- begin TMS_DELETE_TASK_TERMINAL_GROUP_LINK
alter table TMS_DELETE_TASK_TERMINAL_GROUP_LINK add constraint FK_DELTASTERGRO_ON_DELETE_TASK foreign key (DELETE_TASK_ID) references TMS_DELETE_TASK(ID)^
alter table TMS_DELETE_TASK_TERMINAL_GROUP_LINK add constraint FK_DELTASTERGRO_ON_TERMINAL_GROUP foreign key (GROUP_ID) references TMS_TERMINAL_GROUP(ID)^
-- end TMS_DELETE_TASK_TERMINAL_GROUP_LINK
-- begin TMS_DEVICE_PROFILE_ACQUIRER_LINK
alter table TMS_DEVICE_PROFILE_ACQUIRER_LINK add constraint FK_DEVPROACQ_ON_DEVICE_PROFILE foreign key (DEVICE_PROFILE_ID) references TMS_DEVICE_PROFILE(ID)^
alter table TMS_DEVICE_PROFILE_ACQUIRER_LINK add constraint FK_DEVPROACQ_ON_ACQUIRER foreign key (ACQUIRER_ID) references TMSEXT_ACQUIRER(ID)^
-- end TMS_DEVICE_PROFILE_ACQUIRER_LINK
-- begin TMS_DEVICE_PROFILE_APP
alter table TMS_DEVICE_PROFILE_APP add constraint FK_TMS_DEVICE_PROFILE_APP_ON_PROFILE foreign key (PROFILE_ID) references TMS_DEVICE_PROFILE(ID)^
create index IDX_TMS_DEVICE_PROFILE_APP_ON_PROFILE on TMS_DEVICE_PROFILE_APP (PROFILE_ID)^
-- end TMS_DEVICE_PROFILE_APP
-- begin TMS_TERMINAL_PROFILING
alter table TMS_TERMINAL_PROFILING add constraint FK_TMS_TERMINAL_PROFILING_ON_FILE foreign key (FILE) references SYS_FILE(ID)^
create index IDX_TMS_TERMINAL_PROFILING_ON_FILE on TMS_TERMINAL_PROFILING (FILE)^
-- end TMS_TERMINAL_PROFILING
-- begin TMS_TERMINAL_PROFILING_ITEMS
alter table TMS_TERMINAL_PROFILING_ITEMS add constraint FK_TMS_TERMINAL_PROFILING_ITEMS_ON_PROFILING foreign key (PROFILING_ID) references TMS_TERMINAL_PROFILING(ID) on delete CASCADE^
create index IDX_TMS_TERMINAL_PROFILING_ITEMS_ON_PROFILING on TMS_TERMINAL_PROFILING_ITEMS (PROFILING_ID)^
-- end TMS_TERMINAL_PROFILING_ITEMS
-- begin TMS_TERMINAL_GROUP_IMPORT_STAGE
create index IDX_TMS_TERMINAL_GROUP_IMPORT_STAGE_IMPORT on TMS_TERMINAL_GROUP_IMPORT_STAGE (IMPORT_ID)^
create index IDX_TMS_TERMINAL_GROUP_IMPORT_STAGE_SN on TMS_TERMINAL_GROUP_IMPORT_STAGE (IMPORT_ID, SN_NORM)^
create index IDX_TMS_TERMINAL_GROUP_IMPORT_STAGE_CREATE_TS on TMS_TERMINAL_GROUP_IMPORT_STAGE (CREATE_TS)^
-- end TMS_TERMINAL_GROUP_IMPORT_STAGE

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
alter table tms_device_model_application_link rename to TMS_DEVICE_MODEL_APPLICATION_LINK__U48203 ;

View File

@ -0,0 +1 @@
drop table if exists TMS_DEVICE_MODEL_APPLICATION_LINK__U48203 cascade ;

View File

@ -0,0 +1 @@
drop index IDX_TMS_DELETE_TASK_LOG_ON_TERMINAL ;

View File

@ -0,0 +1 @@
drop index IDX_TMS_DIAGNOSTIC_INFO_ON_TERMINAL ;

View File

@ -0,0 +1 @@
drop index IDX_TMS_DOWNLOAD_TASK_LOG_ON_TERMINAL ;

View File

@ -0,0 +1 @@
drop index IDX_TMS_TERMINAL_LINK_ON_TERMINAL ;

View File

@ -0,0 +1 @@
alter table TMS_DELETE_TASK_LOG add constraint FK_TMS_DELETE_TASK_LOG_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID);

View File

@ -0,0 +1,2 @@
alter table TMS_DEVICE_PROFILE_ACQUIRER_LINK drop column "CREATE_TS" cascade ;
alter table TMS_DEVICE_PROFILE_ACQUIRER_LINK drop column "UPDATE_TS" cascade ;

View File

@ -0,0 +1 @@
alter table TMS_DIAGNOSTIC_INFO rename column device_info_ext to device_info_ext__u23585 ;

View File

@ -0,0 +1 @@
alter table TMS_DIAGNOSTIC_INFO drop column DEVICE_INFO_EXT__U23585 cascade ;

View File

@ -0,0 +1 @@
alter table TMS_DOWNLOAD_TASK_LOG add constraint FK_TMS_DOWNLOAD_TASK_LOG_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID);

View File

@ -0,0 +1,3 @@
alter table TMS_HEART_BEAT rename column sn to sn__u07238 ;
-- update TMS_HEART_BEAT set TERMINAL_ID = <default_value> where TERMINAL_ID is null ;
alter table TMS_HEART_BEAT alter column TERMINAL_ID set not null ;

View File

@ -0,0 +1,2 @@
alter table TMS_HEART_BEAT add constraint FK_TMS_HEART_BEAT_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID);
create index IDX_TMS_HEART_BEAT_ON_TERMINAL on TMS_HEART_BEAT (TERMINAL_ID);

View File

@ -0,0 +1 @@
alter table TMS_HEART_BEAT drop column SN__U07238 cascade ;

View File

@ -0,0 +1,7 @@
alter table TMS_TERMINAL rename column vendor_name to vendor_name__u88543 ;
alter table TMS_TERMINAL rename column battery_percentage to battery_percentage__u35652 ;
alter table TMS_TERMINAL rename column battery_temp to battery_temp__u40460 ;
alter table TMS_TERMINAL rename column cell_strength to cell_strength__u43461 ;
alter table TMS_TERMINAL rename column cell_type to cell_type__u93575 ;
alter table TMS_TERMINAL rename column host_report to host_report__u04927 ;
alter table TMS_TERMINAL alter column CELL_NAME set data type varchar(255) ;

View File

@ -0,0 +1 @@
alter table TMS_TERMINAL_LINK add constraint FK_TMS_TERMINAL_LINK_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID);

View File

@ -0,0 +1,6 @@
alter table TMS_TERMINAL drop column HOST_REPORT__U04927 cascade ;
alter table TMS_TERMINAL drop column CELL_TYPE__U93575 cascade ;
alter table TMS_TERMINAL drop column CELL_STRENGTH__U43461 cascade ;
alter table TMS_TERMINAL drop column BATTERY_TEMP__U40460 cascade ;
alter table TMS_TERMINAL drop column BATTERY_PERCENTAGE__U35652 cascade ;
alter table TMS_TERMINAL drop column VENDOR_NAME__U88543 cascade ;

View File

@ -0,0 +1,2 @@
alter table TMSEXT_TERMINAL_EXT rename column _terminal_id to _terminal_id__u67496 ;
alter table TMSEXT_TERMINAL_EXT rename column import_default to import_default__u88120 ;

View File

@ -0,0 +1,2 @@
alter table TMSEXT_TERMINAL_EXT drop column IMPORT_DEFAULT__U88120 cascade ;
alter table TMSEXT_TERMINAL_EXT drop column _TERMINAL_ID__U67496 cascade ;

View File

@ -0,0 +1,15 @@
create table TMS_TERMINAL_GROUP_IMPORT_STAGE (
IMPORT_ID uuid not null,
ROW_NO integer not null,
CREATE_TS timestamp default current_timestamp,
TID varchar(255),
SN varchar(255),
TID_NORM varchar(255),
SN_NORM varchar(255),
SN_LOWER_NORM varchar(255),
primary key (IMPORT_ID, ROW_NO)
);
create index IDX_TMS_TERMINAL_GROUP_IMPORT_STAGE_IMPORT on TMS_TERMINAL_GROUP_IMPORT_STAGE (IMPORT_ID);
create index IDX_TMS_TERMINAL_GROUP_IMPORT_STAGE_SN on TMS_TERMINAL_GROUP_IMPORT_STAGE (IMPORT_ID, SN_NORM);
create index IDX_TMS_TERMINAL_GROUP_IMPORT_STAGE_CREATE_TS on TMS_TERMINAL_GROUP_IMPORT_STAGE (CREATE_TS);

View File

@ -0,0 +1 @@
alter table TMS_TERMINAL_GROUP_IMPORT_STAGE add column if not exists SN_LOWER_NORM varchar(255);

View File

@ -0,0 +1,48 @@
package com.cmobile.unifiedtms;
import com.haulmont.cuba.core.config.Config;
import com.haulmont.cuba.core.config.Property;
import com.haulmont.cuba.core.config.Source;
import com.haulmont.cuba.core.config.SourceType;
import com.haulmont.cuba.core.config.defaults.Default;
import com.haulmont.cuba.core.global.Secret;
@Source(type = SourceType.DATABASE)
public interface MqttConfig extends Config {
@Property("mqtt.enabled")
Boolean getMqttEnabled();
@Property("mqtt.brokerUrl")
String getBrokerURL();
@Property("mqtt.clientId")
String getClientId();
@Property("mqtt.username")
String getUsername();
@Property("mqtt.password")
@Secret
String getPassword();
@Property("mqtt.incomingMessageTopic")
@Default(value = "SERVER_IN")
String getIncomingMessageTopic();
@Property("mqtt.autoReconnect")
@Default(value = "true")
Boolean getAutoReconnect();
@Property("mqtt.keepAliveInterval")
@Default(value = "10000")
Integer getKeepAliveInterval();
@Property("mqtt.disconnectTimeout")
@Default(value = "5000")
Long getDisconnectTimeout();
@Property("mqtt.device-host")
String getDeviceHost();
}

View File

@ -0,0 +1,30 @@
package com.cmobile.unifiedtms;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public final class Singleton {
private final static Map<String, Singleton> INSTANCES = new HashMap<>();
private Object object;
private Singleton() {}
public void setObject(Object object) {
this.object = object;
}
public Object getObject() {
return object;
}
public static Singleton getInstance(String name) {
Singleton instance = INSTANCES.get(name);
if(instance == null) {
instance = new Singleton();
INSTANCES.put(name, instance);
}
return instance;
}
}

View File

@ -0,0 +1,46 @@
###############################################################################
# Configuration #
###############################################################################
cuba.dbmsType = postgres
cuba.springContextConfig = +com/cmobile/unifiedtms/spring.xml
cuba.persistenceConfig = +com/cmobile/unifiedtms/persistence.xml
cuba.metadataConfig = +com/cmobile/unifiedtms/metadata.xml
cuba.viewsConfig = +com/cmobile/unifiedtms/views.xml
cuba.mainMessagePack = +com.cmobile.unifiedtms.core
cuba.keyForSecurityTokenEncryption = 9WMPJQzNkeWDe90V
cuba.anonymousSessionId = 3aa2d4b1-205c-de8c-bcb6-f4153ae617c7
###############################################################################
# Other #
###############################################################################
cuba.webContextName = tms-core
cuba.availableLocales = English|en;Indonesian (Indonesia)|id_ID
cuba.localeSelectVisible = false
cuba.dataSourceProvider = application
cuba.dataSource.username = utms
cuba.dataSource.password = utms1234
cuba.dataSource.dbName = utms
cuba.dataSource.host = localhost
cuba.dataSource.port =
# Multi Tenancy
cubasdbmt.loginByTenantParamEnabled = true
cubasdbmt.tenantIdUrlParamName = tenantId
cuba.ftsConfig=+com/cmobile/unifiedtms/fts.xml
#license.concurrentSessionsLimit = 1
#cuba.legacyPasswordEncryptionModule = cuba_Md5EncryptionModule
#cuba.passwordEncryptionModule = cuba_Md5EncryptionModule
#whitelist.package.names = (com.vfi.*|com.briit.*|com.unified.*|com.klopos.*|id.co.bri.*)
#blacklist.threshold = 5

View File

@ -0,0 +1,16 @@
package com.cmobile.unifiedtms.config;
import com.haulmont.cuba.core.config.Config;
import com.haulmont.cuba.core.config.Property;
import com.haulmont.cuba.core.config.Source;
import com.haulmont.cuba.core.config.SourceType;
import com.haulmont.cuba.core.config.defaults.Default;
@Source(type = SourceType.DATABASE)
public interface LicenseConfig extends Config {
@Property("unified.license.string")
String getLicenseString();
void setLicenseString(String licenseString);
}

View File

@ -0,0 +1,24 @@
package com.cmobile.unifiedtms.core.config;
import com.haulmont.cuba.core.config.Config;
import com.haulmont.cuba.core.config.Property;
import com.haulmont.cuba.core.config.Source;
import com.haulmont.cuba.core.config.SourceType;
import com.haulmont.cuba.core.config.defaults.Default;
@Source(type = SourceType.DATABASE)
public interface EchoTestConfig extends Config {
@Property("mqtt.echo.missing.max")
@Default("3")
Integer getEchoMissingMax();
@Property("mqtt.echo.missing.after")
@Default("10000")
Long getEchoMissingAfter();
@Property("mqtt.echo.sleep")
@Default("1000")
Long getEchoCheckSleep();
}

View File

@ -0,0 +1,21 @@
package com.cmobile.unifiedtms.core.config;
import com.haulmont.cuba.core.config.Config;
import com.haulmont.cuba.core.config.Property;
import com.haulmont.cuba.core.config.Source;
import com.haulmont.cuba.core.config.SourceType;
import com.haulmont.cuba.core.config.defaults.Default;
import com.haulmont.cuba.core.config.defaults.DefaultInt;
@Source(type = SourceType.DATABASE)
public interface ExtendedConfig extends Config {
@Property("whitelist.package.names")
@Default("(.*)")
String getWhitelistPackageNames();
@Property("blacklist.threshold")
@DefaultInt(5)
int getBlacklistThreshold();
}

View File

@ -0,0 +1,16 @@
package com.cmobile.unifiedtms.core.config;
import com.haulmont.cuba.core.config.Config;
import com.haulmont.cuba.core.config.Property;
import com.haulmont.cuba.core.config.Source;
import com.haulmont.cuba.core.config.SourceType;
import com.haulmont.cuba.core.config.defaults.Default;
@Source(type = SourceType.DATABASE)
public interface FileDownloadConfig extends Config {
@Property("unified.filedownload.url")
@Default("https://unifiedtms.id/download/services/file/get?id={$id}")
String getFileDownloadURL();
}

View File

@ -0,0 +1,25 @@
package com.cmobile.unifiedtms.core.config;
import com.haulmont.cuba.core.config.Config;
import com.haulmont.cuba.core.config.Property;
import com.haulmont.cuba.core.config.Source;
import com.haulmont.cuba.core.config.SourceType;
import com.haulmont.cuba.core.config.defaults.DefaultBoolean;
import com.haulmont.cuba.core.config.defaults.DefaultString;
@Source(type = SourceType.DATABASE)
public interface TerminalUpdateConfig extends Config {
@Property("utms.force.terminal-update")
@DefaultBoolean(false)
Boolean getForceUpdate();
@Property("utms.force.terminal-not-update")
@DefaultBoolean(false)
Boolean getForceNotUpdate();
@Property("utms.force.terminal-update.mode")
@DefaultString("NORMAL")
String getForceNotUpdateMode();
}

View File

@ -0,0 +1,23 @@
package com.cmobile.unifiedtms.core.mqtt;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class BlindTrustManager implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
}

View File

@ -0,0 +1,265 @@
package com.cmobile.unifiedtms.core.mqtt;
import com.cmobile.unifiedtms.MqttConfig;
import com.cmobile.unifiedtms.core.config.EchoTestConfig;
import com.cmobile.unifiedtms.core.config.FileDownloadConfig;
import com.cmobile.unifiedtms.core.mqtt.listener.*;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.security.app.Authentication;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@Component(MqttConnector.NAME)
public class MqttConnector<LoginService> {
public static final String NAME = "tms_MQTTConnector";
@Inject
private Logger logger;
@Inject
private MqttConfig mqttConfig;
@Inject
private Authentication authentication;
@Inject
private FileDownloadConfig fileDownloadConfig;
@Inject
private EchoTestConfig echoTestConfig;
@Inject
private Persistence persistence;
private MqttClient mqttClient;
private List<IncomingMessageListener> messageListeners = new ArrayList<>();
private AtomicBoolean echoTesterStarted = new AtomicBoolean(false);
private ExecutorService exec = Executors.newSingleThreadExecutor();
private Date lastEchoReceivedTime = null;
private Date echoCheckStartedTime = null;
private AtomicInteger echoMissing = new AtomicInteger(0);
@PostConstruct
public void postConstruct() {
logger.debug("#postConstruct");
try {
logger.debug("-> mqtt enabled? {}", mqttConfig.getMqttEnabled());
if(mqttConfig.getMqttEnabled() != null && mqttConfig.getMqttEnabled()) {
connectAndListen();
addDefaultListeners();
//startEchoTestMaintainer();
}
} catch(Exception ex) {
logger.error("Cannot init & connecting MQTT Client: " + ex.getMessage(), ex);
}
}
private MqttClient initClient() throws Exception {
logger.debug("Initialize MQTT Client ...");
try {
MemoryPersistence persistence = new MemoryPersistence();
MqttClient _mqttClient = new MqttClient(mqttConfig.getBrokerURL(),
//mqttConfig.getClientId(),
MqttAsyncClient.generateClientId(),
persistence);
_mqttClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean bln, String string) {
//System.out.println("Connect complete? " + bln + " : " + string);
try {
_mqttClient.subscribe(mqttConfig.getIncomingMessageTopic());
} catch(Exception ex) {
logger.error("Error subscribe topic: " + mqttConfig.getIncomingMessageTopic());
}
}
@Override
public void connectionLost(Throwable thrwbl) {
logger.error("Connection Lost: " + thrwbl);
}
@Override
public void messageArrived(String topic, MqttMessage mm) throws Exception {
logger.debug("<< " + new String(mm.getPayload()) + " (" + mm.getId() + " - " + mm.getQos() + ")");
String messageString = new String(mm.getPayload());
for(IncomingMessageListener listener : messageListeners) {
boolean handled = listener.incomingMessage(MqttConnector.this, topic, messageString);
if(handled) {
break;
}
}
//mm.setRetained(false);
}
@Override
public void deliveryComplete(IMqttDeliveryToken imdt) {
System.err.println("Delivery Complete: " + imdt.getMessageId());
}
});
logger.debug("MQTT Client Initialized.");
return _mqttClient;
} catch (MqttException me) {
throw me;
} finally {
}
}
private void connectAndListen() throws Exception {
logger.debug("Connect to Broker and Listen for incoming messages ...");
if(mqttClient == null) {
mqttClient = initClient();
}
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setUserName(mqttConfig.getUsername());
connOpts.setPassword(mqttConfig.getPassword().toCharArray());
connOpts.setAutomaticReconnect(mqttConfig.getAutoReconnect());
connOpts.setKeepAliveInterval(mqttConfig.getKeepAliveInterval());
if(mqttConfig.getBrokerURL().toLowerCase().contains("ssl://")) {
connOpts.setSocketFactory(buildSocketFactory());
}
mqttClient.connect(connOpts);
}
private void addDefaultListeners() throws Exception {
// pending task push listener will always return false so it will continue
// to other listeners
//PendingTaskPushListener ptpl = new PendingTaskPushListener(authentication);
//ptpl.setFileDownloadConfig(fileDownloadConfig);
//addIncomingMessageListener(ptpl);
addIncomingMessageListener(new HeartBeatListener(authentication));
addIncomingMessageListener(new DiagnosticInfoListener(authentication));
DownloadTaskAckListener dtl = new DownloadTaskAckListener(authentication);
dtl.setPersistence(persistence);
addIncomingMessageListener(dtl);
DeleteTaskAckListener deltl = new DeleteTaskAckListener(authentication);
deltl.setPersistence(persistence);
addIncomingMessageListener(deltl);
addIncomingMessageListener(new DeviceInitListener(authentication));
addIncomingMessageListener(new EchoListener());
}
private void startEchoTestMaintainer() throws Exception {
logger.debug("Start Echo Test Maintainer ...");
Runnable run = new Runnable() {
@Override
public void run() {
boolean set = echoTesterStarted.compareAndSet(false, true);
echoCheckStartedTime = new Date();
logger.debug("Set? {}", set);
logger.debug("Echo Check Start ...");
while(echoTesterStarted.get()) {
logger.debug("Echo Check ...");
if(mqttClient != null) {
if(lastEchoReceivedTime == null) {
lastEchoReceivedTime = echoCheckStartedTime;
}
Date now = new Date();
long echoMissingAfter = echoTestConfig.getEchoMissingAfter();
long timeSentMS = lastEchoReceivedTime.getTime();
long nowMS = now.getTime();
long diff = nowMS - timeSentMS;
boolean expired = diff >= echoMissingAfter;
logger.debug("Last Echo received: {} - {} ; Expired after {}? {}", lastEchoReceivedTime, now, echoMissingAfter, expired);
if(expired) {
int maxEchoMissing = echoTestConfig.getEchoMissingMax();
int echoMissingCount = echoMissing.incrementAndGet();
logger.debug("Missed Echo: {} x {}", echoMissingCount, maxEchoMissing);
// restart mqttclient if max reached
if(echoMissingCount >= maxEchoMissing) {
try {
logger.debug("Forcibly disconnect Mqtt ...");
mqttClient.disconnectForcibly();
mqttClient.close(true);
mqttClient = null;
lastEchoReceivedTime = null;
echoMissing.set(0);
// sleep for 1000 ms
TimeUnit.MILLISECONDS.sleep(1000);
logger.debug("... then re-connect!");
connectAndListen();
echoCheckStartedTime = new Date();
} catch (Exception ex) {
logger.error("Error restart Mqtt Client: {}", ex.getMessage(), ex);
}
} else {
lastEchoReceivedTime = new Date();
}
}
} else {
logger.debug("Maybe still re-connecting: no check!");
}
try {
long sleep = echoTestConfig.getEchoCheckSleep();
logger.debug("Sleep for {} ms", sleep);
TimeUnit.MILLISECONDS.sleep(sleep);
} catch(InterruptedException ex) {
logger.error("Echo Test Check got interrupted!!", ex);
}
}
logger.debug("Echo Check Ended ...");
}
};
exec.submit(run);
}
public void echoReceived(Date timeSent) {
this.lastEchoReceivedTime = timeSent;
}
public void addIncomingMessageListener(IncomingMessageListener listener) {
messageListeners.add(listener);
}
public void disconnect() throws Exception {
logger.debug("Disconnect before waiting for {} ms", mqttConfig.getDisconnectTimeout());
if(mqttClient != null) {
mqttClient.disconnectForcibly(mqttConfig.getDisconnectTimeout());
}
}
public void publishMessage(String topic, String messageData, int qos) throws Exception {
publishMessage(topic, messageData.getBytes(), qos, false);
}
public void publishRetainedMessage(String topic, String messageData, int qos) throws Exception {
publishMessage(topic, messageData.getBytes(), qos, true);
}
public void publishMessage(String topic, byte[] bytes, int qos, boolean retained) throws Exception {
if(mqttClient == null) {
mqttClient = initClient();
connectAndListen();
} else if(!mqttClient.isConnected()) {
connectAndListen();
}
MqttMessage message = new MqttMessage(bytes);
message.setRetained(retained);
message.setQos(qos);
logger.debug(">> {}", new String(bytes));
mqttClient.publish(topic, message);
}
private SSLSocketFactory buildSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(null, new TrustManager[] { new BlindTrustManager() }, null);
return ctx.getSocketFactory();
}
}

View File

@ -0,0 +1,219 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.DeleteTask;
import com.cmobile.unifiedtms.entity.DeleteTaskLog;
import com.cmobile.unifiedtms.entity.DownloadTask;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.enums.DeleteTaskActivity;
import com.cmobile.unifiedtms.entity.enums.TaskStatus;
import com.google.gson.Gson;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.security.app.Authentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
public class DeleteTaskAckListener implements IncomingMessageListener {
private Logger logger = LoggerFactory.getLogger(DeleteTaskAckListener.class);
private Authentication authentication;
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
private Persistence persistence;
public DeleteTaskAckListener(Authentication authentication) {
this.authentication = authentication;
}
public void setPersistence(Persistence persistence) {
this.persistence = persistence;
}
@Override
public boolean incomingMessage(MqttConnector connector, String topic, String message) {
try {
String json = message;
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
logger.debug("Incoming MAP: " + map);
logger.debug("Before Authentication ...");
authentication.begin();
logger.debug("Authenticated");
String type = (String) map.get("req_type");
if("ACK_DELETE_APP_TASK".equals(type)) {
logger.debug("Detected Incoming: Ack of Delete Task ...");
UUID reqId = UUID.fromString((String) map.get("req_id"));
reqId = UUID.randomUUID();
String terminalSN = (String) map.get("device_sn");
Terminal terminal = loadTerminalBySN(terminalSN);
UUID ackId = UUID.fromString((String) map.get("ack_id"));
DeleteTaskLog log = loadDeleteTaskLog(ackId);
if(terminal != null) {
if(log != null) {
String status = (String) map.get("status");
if("ACCEPTED".equals(status)) {
status = "NOT_STARTED";
}
DeleteTaskActivity activity = DeleteTaskActivity.valueOf(status);
log.setActivity(activity);
boolean saved = commitToDB(log);
logger.debug("Save Ack to DB: " + saved);
if(saved) {
if("DELETE_SUCCESS".equals(status) ||
"DELETE_FAIL".equals(status)) {
// send ack DELETE_TASK_CONFIRM_ACK
broadcastDeleteTasksConfirmACK(connector, terminalSN, ackId);
}
int totalUnfinishedTask = getUnfinishedTask(log.getTask().getId());
if(totalUnfinishedTask == 0) {
// mark task as complete
DeleteTask task = log.getTask();
task.setStatus(TaskStatus.DONE);
boolean taskCommitted = commitToDB(task);
logger.debug("Save Task to DB: " + taskCommitted);
}
}
} else {
logger.warn("Invalid Delete Task Log (will give successful ack): {}", ackId);
// send ack DELETE_TASK_CONFIRM_ACK
broadcastDeleteTasksConfirmACK(connector, terminalSN, ackId);
}
} else {
logger.warn("Invalid Terminal: {}", terminalSN);
}
return true;
} else {
// not my part
}
} catch(Exception ex) {
logger.error("Error handling incoming message: {}", ex.getMessage(), ex);
} finally {
authentication.end();
}
return false;
}
private Integer getUnfinishedTask(UUID downloadTaskId) {
Double value = _getValueFromQuery("select count(*) from public.tms_delete_task_log where task_id = '" + downloadTaskId.toString() + "' and activity not in (3,4);");
logger.debug("--> value: '" + value + "'");
return value != null ? value.intValue() : null;
}
private Double _getValueFromQuery(String query) {
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
Set<Double> numbers = runner.query(query,
new ResultSetHandler<Set<Double>>() {
@Nullable
@Override
public Set<Double> handle(ResultSet rs) throws SQLException {
Set<Double> rows = new HashSet<Double>();
while (rs.next()) {
rows.add(rs.getDouble(1));
}
return rows;
}
});
return numbers.isEmpty() ? null : numbers.toArray(new Double[] {})[0];
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
// send download task to device topic via mqtt
public void broadcastDeleteTasksConfirmACK(MqttConnector mqttConnector,
String terminalSN,
UUID ackId) throws Exception {
logger.debug("Broadcast tasks ...");
try {
try {
int qos = 2;
String topicName = terminalSN.toUpperCase() + "_IN";
// generate json
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
// we'll use log's id as ack_id
messageMap.put("ack_id", ackId.toString());
messageMap.put("req_type", "DELETE_TASK_CONFIRM_ACK");
String messageData = gson.toJson(messageMap);
logger.debug("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.debug("Message published!");
} catch(Exception ex) {
logger.error("Error publish to device: {}", ex.getMessage(), ex);
} finally {
}
} finally {
logger.debug("Start broadcast download tasks DONE");
}
}
private int getInt(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
return Integer.parseInt((String) val);
} else if(val instanceof Integer) {
return (Integer) val;
} else if(val instanceof Double) {
return ((Double) val).intValue();
}
return 0;
}
private String getString(Map map, String key) {
return (String) map.get(key);
}
private boolean commitToDB(DeleteTaskLog log) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
DeleteTaskLog committed = dataManager.commit(log);
//return PersistenceHelper.isManaged(committed);
return committed != null;
}
private boolean commitToDB(DeleteTask task) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
DeleteTask committed = dataManager.commit(task);
//return PersistenceHelper.isManaged(committed);
return committed != null;
}
private Terminal loadTerminalBySN(String terminalSN) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn)=:sn and t.deleteTs is null");
loadContext.getQuery().setParameter("sn", terminalSN.toLowerCase());
return dataManager.load(loadContext);
}
private DeleteTaskLog loadDeleteTaskLog(UUID logId) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<DeleteTaskLog> loadContext = LoadContext.create(DeleteTaskLog.class);
loadContext.setQueryString("select t from tms_DeleteTaskLog t where t.id=:id");
loadContext.getQuery().setParameter("id", logId);
loadContext.setView("deleteTaskLog-view");
return dataManager.load(loadContext);
}
}

View File

@ -0,0 +1,135 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.DeviceProfile;
import com.cmobile.unifiedtms.entity.HeartBeat;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.enums.DownloadTaskType;
import com.cmobile.unifiedtms.entity.enums.DownloadTimeType;
import com.cmobile.unifiedtms.entity.enums.InstallationTimeType;
import com.google.gson.Gson;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.PersistenceHelper;
import com.haulmont.cuba.security.app.Authentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class DeviceInitListener implements IncomingMessageListener {
private Logger logger = LoggerFactory.getLogger(DeviceInitListener.class);
private Authentication authentication;
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
public DeviceInitListener(Authentication authentication) {
this.authentication = authentication;
}
@Override
public boolean incomingMessage(MqttConnector connector, String topic, String message) {
try {
String json = message;
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
logger.debug("Incoming MAP: " + map);
logger.debug("Before Authentication ...");
authentication.begin();
logger.debug("Authenticated");
String type = (String) map.get("req_type");
if("INIT".equals(type)) {
logger.debug("Detected Incoming: Init ...");
UUID reqId = UUID.fromString((String) map.get("req_id"));
reqId = UUID.randomUUID();
String terminalSN = (String) map.get("device_sn");
Terminal terminal = loadTerminalBySN(terminalSN);
if(terminal != null) {
// get terminal's profile
DeviceProfile profile = terminal.getProfile();
if(profile != null) {
int qos = 2;
String topicName = terminal.getSn().toUpperCase() + "_IN";
// generate json
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
messageMap.put("req_type", "UPDATE_PARAM");
// profile map
Map profileMap = new HashMap<>();
profileMap.put("id", profile.getId().toString());
profileMap.put("name", profile.getName());
profileMap.put("hearbeat_interval", profile.getHeartbeatInterval());
profileMap.put("diagnostic_interval", profile.getDiagnosticInterval());
profileMap.put("mask_home_button", profile.getMaskHomeButton());
profileMap.put("mask_status_button", profile.getMaskStatusBar());
profileMap.put("schedule_reboot", profile.getScheduleReboot());
if (profile.getScheduleReboot()) {
profileMap.put("schedule_reboot_time", timeFormat.format(profile.getScheduleRebootTime()));
}
profileMap.put("relocation_alert", profile.getRelocationAlert());
profileMap.put("moving_threshold", profile.getMovingThreshold());
profileMap.put("admin_password", profile.getAdminPassword());
messageMap.put("profile", profileMap);
String messageData = gson.toJson(messageMap);
logger.debug("Try publish message to: {}", topicName);
connector.publishRetainedMessage(topicName, messageData, qos);
logger.debug("Message published!");
} else {
logger.debug("Device has no profile: {}", terminal.getSn());
}
} else {
logger.debug("Invalid Terminal: {}", terminalSN);
}
return true;
} else {
// not my part
}
} catch(Exception ex) {
logger.error("Error handling incoming message: {}", ex.getMessage(), ex);
} finally {
authentication.end();
}
return false;
}
private int getInt(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
return Integer.parseInt((String) val);
} else if(val instanceof Integer) {
return (Integer) val;
} else if(val instanceof Double) {
return ((Double) val).intValue();
}
return 0;
}
private boolean commitToDB(HeartBeat heartBeat) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
HeartBeat committed = dataManager.commit(heartBeat);
return PersistenceHelper.isManaged(committed);
}
private Terminal loadTerminalBySN(String terminalSN) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn)=:sn and t.deleteTs is null");
loadContext.getQuery().setParameter("sn", terminalSN.toLowerCase());
loadContext.setView("terminal-with-profile-view");
return dataManager.load(loadContext);
}
}

View File

@ -0,0 +1,197 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.ApplicationSimple;
import com.cmobile.unifiedtms.entity.DiagnosticInfo;
import com.cmobile.unifiedtms.entity.HeartBeat;
import com.cmobile.unifiedtms.entity.Terminal;
import com.google.gson.Gson;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.security.app.Authentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.*;
public class DiagnosticInfoListener implements IncomingMessageListener {
private Logger logger = LoggerFactory.getLogger(DiagnosticInfoListener.class);
private Authentication authentication;
public DiagnosticInfoListener(Authentication authentication) {
this.authentication = authentication;
}
@Override
public boolean incomingMessage(MqttConnector connector, String topic, String message) {
try {
String json = message;
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
logger.info("Incoming MAP: " + map);
logger.info("Before Authentication ...");
authentication.begin();
logger.info("Authenticated");
String type = (String) map.get("req_type");
if("DIAGNOSTIC".equals(type)) {
logger.info("Detected Incoming: Diagnostic Info ...");
UUID reqId = UUID.fromString((String) map.get("req_id"));
reqId = UUID.randomUUID();
String terminalSN = (String) map.get("device_sn");
DiagnosticInfo diagnosticInfo = new DiagnosticInfo();
diagnosticInfo.setId(reqId);
diagnosticInfo.setCreateTs(new Date());
diagnosticInfo.setCreatedBy(terminalSN);
diagnosticInfo.setVersion(1);
Terminal terminal = loadTerminalBySN(terminalSN);
if(terminal != null) {
// diagnostic info - mandatory
Map diagnosticInfoMap = (Map) map.get("diagnostic_info");
boolean isNewDiagnostic = getBoolean(diagnosticInfoMap, "new_diagnostic");
diagnosticInfo.setTerminal(terminal);
diagnosticInfo.setBatteryPercentage(getInt(diagnosticInfoMap, "battery_percentage"));
double temp = getDouble(diagnosticInfoMap, "battery_temp");
// handel temp for new diagnostic
if(isNewDiagnostic) {
temp /= 10;
}
diagnosticInfo.setBatteryTemp(temp);
diagnosticInfo.setMeid((String) diagnosticInfoMap.get("meid"));
diagnosticInfo.setTotalMemory(getLong(diagnosticInfoMap, "total_memory"));
diagnosticInfo.setAvailableMemory(getLong(diagnosticInfoMap, "available_memory"));
diagnosticInfo.setTotalFlashMemory(getLong(diagnosticInfoMap, "total_flash_memory"));
diagnosticInfo.setAvailableFlashMemory(getLong(diagnosticInfoMap, "available_flash_memory"));
diagnosticInfo.setTotalMobileData(getLong(diagnosticInfoMap, "total_mobile_data"));
diagnosticInfo.setCurrentBootTime(getInt(diagnosticInfoMap, "current_boot_time"));
diagnosticInfo.setTotalBootTime(getInt(diagnosticInfoMap, "total_boot_time"));
diagnosticInfo.setTotalLengthPrinted(getDouble(diagnosticInfoMap, "total_length_printed"));
diagnosticInfo.setSwitchingTimes(getInt(diagnosticInfoMap, "switching_times"));
diagnosticInfo.setSwipingCardTimes(getInt(diagnosticInfoMap, "swiping_card_times"));
diagnosticInfo.setDipInsertingTimes(getInt(diagnosticInfoMap, "dip_inserting_times"));
diagnosticInfo.setNfcCardReadingTimes(getInt(diagnosticInfoMap, "nfc_card_reading_times"));
diagnosticInfo.setFrontCameraOpenTimes(getInt(diagnosticInfoMap, "front_camera_open_times"));
diagnosticInfo.setRearCameraOpenTimes(getInt(diagnosticInfoMap, "rear_camera_open_times"));
diagnosticInfo.setChargeTimes(getInt(diagnosticInfoMap, "charge_times"));
// installed apps
List<Map<String, Object>> installedApps = (List<Map<String, Object>>) map.get("installed_apps");
if(installedApps != null) {
Metadata metadata = AppBeans.get(Metadata.NAME);
List<ApplicationSimple> applications = new ArrayList<>();
installedApps.forEach(appMap -> {
String appName = getString(appMap, "app_name");
String packageName = getString(appMap, "package_name");
String version = getString(appMap, "version");
ApplicationSimple appSimple = metadata.create(ApplicationSimple.class);
appSimple.setAppName(appName);
appSimple.setPackageName(packageName);
appSimple.setAppVersion(version);
appSimple.setDiagnosticInfo(diagnosticInfo);
applications.add(appSimple);
});
diagnosticInfo.setInstalledApps(applications);
String installedAppsJson = gson.toJson(installedApps);
diagnosticInfo.setInstalledAppsString(installedAppsJson);
}
// location info - mandatory
Map locationInfoMap = (Map) map.get("location_info");
diagnosticInfo.setLatitude((Double) locationInfoMap.get("lat"));
diagnosticInfo.setLongitude((Double) locationInfoMap.get("lng"));
boolean saved = commitToDB(diagnosticInfo);
logger.info("Save Diagnostic Info to DB: " + saved);
} else {
logger.info("Invalid Terminal: {}", terminalSN);
}
return true;
} else {
// not my part
}
} catch(Exception ex) {
logger.error("Error handling incoming message: {}", ex.getMessage(), ex);
} finally {
authentication.end();
}
return false;
}
private boolean getBoolean(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
String sVal = (String) val;
return Boolean.parseBoolean(sVal.trim());
} else if(val instanceof Boolean) {
return (Boolean) val;
}
return false;
}
private double getDouble(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
String sVal = (String) val;
return Double.parseDouble(sVal.trim());
} else if(val instanceof Double) {
return (Double) val;
} else if(val instanceof Integer) {
return (Double) val;
}
return 0.0;
}
private int getInt(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
String sVal = (String) val;
return Integer.parseInt(sVal.trim());
} else if(val instanceof Integer) {
return (Integer) val;
} else if(val instanceof Double) {
return ((Double) val).intValue();
}
return 0;
}
private long getLong(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
String sVal = (String) val;
if(sVal.contains("B")) {
sVal = sVal.replace("B", "");
}
return Long.parseLong(sVal.trim());
} else if(val instanceof Long) {
return (Long) val;
} else if(val instanceof Double) {
return ((Double) val).longValue();
}
return 0;
}
private String getString(Map map, String key) {
return (String) map.get(key);
}
private boolean commitToDB(DiagnosticInfo diagnosticInfo) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
HeartBeat committed = dataManager.commit(diagnosticInfo);
return PersistenceHelper.isManaged(committed);
}
private Terminal loadTerminalBySN(String terminalSN) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn)=:sn and t.deleteTs is null");
loadContext.getQuery().setParameter("sn", terminalSN.toLowerCase());
return dataManager.load(loadContext);
}
}

View File

@ -0,0 +1,223 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.Application;
import com.cmobile.unifiedtms.entity.DownloadTask;
import com.cmobile.unifiedtms.entity.DownloadTaskLog;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.enums.DownloadTaskActivity;
import com.cmobile.unifiedtms.entity.enums.DownloadTimeType;
import com.cmobile.unifiedtms.entity.enums.InstallationTimeType;
import com.cmobile.unifiedtms.entity.enums.TaskStatus;
import com.google.gson.Gson;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.app.LockService;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.security.app.Authentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
public class DownloadTaskAckListener implements IncomingMessageListener {
private Logger logger = LoggerFactory.getLogger(DownloadTaskAckListener.class);
private Authentication authentication;
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
private Persistence persistence;
public DownloadTaskAckListener(Authentication authentication) {
this.authentication = authentication;
}
public void setPersistence(Persistence persistence) {
this.persistence = persistence;
}
@Override
public boolean incomingMessage(MqttConnector connector, String topic, String message) {
try {
String json = message;
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
logger.debug("Incoming MAP: " + map);
logger.debug("Before Authentication ...");
authentication.begin();
logger.debug("Authenticated");
String type = (String) map.get("req_type");
if("ACK_DOWNLOAD_APP_TASK".equals(type)) {
logger.debug("Detected Incoming: Ack of Download Task ...");
UUID reqId = UUID.fromString((String) map.get("req_id"));
reqId = UUID.randomUUID();
String terminalSN = (String) map.get("device_sn");
Terminal terminal = loadTerminalBySN(terminalSN);
UUID ackId = UUID.fromString((String) map.get("ack_id"));
DownloadTaskLog log = loadDownloadTaskLog(ackId);
if(terminal != null) {
if(log != null) {
String status = (String) map.get("status");
if("ACCEPTED".equals(status)) {
status = "NOT_STARTED";
}
DownloadTaskActivity activity = DownloadTaskActivity.valueOf(status);
log.setActivity(activity);
boolean saved = commitToDB(log);
logger.debug("Save Ack to DB: " + saved);
if(saved) {
if("INSTALL_SUCCESS".equals(status) ||
"INSTALL_FAIL".equals(status)) {
// send ack DOWNLOAD_TASK_CONFIRM_ACK
broadcastDownloadTasksConfirmACK(connector, terminalSN, ackId);
}
int totalUnfinishedTask = getUnfinishedTask(log.getTask().getId());
if(totalUnfinishedTask == 0) {
// mark task as complete
DownloadTask task = log.getTask();
task.setStatus(TaskStatus.DONE);
boolean taskCommitted = commitToDB(task);
logger.debug("Save Task to DB: " + taskCommitted);
}
}
} else {
logger.warn("Invalid Download Task Log (will give successful response): {}", ackId);
// send ack DOWNLOAD_TASK_CONFIRM_ACK
broadcastDownloadTasksConfirmACK(connector, terminalSN, ackId);
}
} else {
logger.warn("Invalid Terminal: {}", terminalSN);
}
return true;
} else {
// not my part
}
} catch(Exception ex) {
logger.error("Error handling incoming message: {}", ex.getMessage(), ex);
} finally {
authentication.end();
}
return false;
}
// send download task to device topic via mqtt
public void broadcastDownloadTasksConfirmACK(MqttConnector mqttConnector,
String terminalSN,
UUID ackId) throws Exception {
logger.debug("Broadcast tasks ...");
try {
try {
int qos = 2;
String topicName = terminalSN.toUpperCase() + "_IN";
// generate json
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
// we'll use log's id as ack_id
messageMap.put("ack_id", ackId.toString());
messageMap.put("req_type", "DOWNLOAD_TASK_CONFIRM_ACK");
String messageData = gson.toJson(messageMap);
logger.debug("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.debug("Message published!");
} catch(Exception ex) {
logger.error("Error publish to device: {}", ex.getMessage(), ex);
} finally {
}
} finally {
logger.debug("Start broadcast download tasks DONE");
}
}
private int getInt(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
return Integer.parseInt((String) val);
} else if(val instanceof Integer) {
return (Integer) val;
} else if(val instanceof Double) {
return ((Double) val).intValue();
}
return 0;
}
private String getString(Map map, String key) {
return (String) map.get(key);
}
private boolean commitToDB(DownloadTaskLog log) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
DownloadTaskLog committed = dataManager.commit(log);
//return PersistenceHelper.isManaged(committed);
return committed != null;
}
private boolean commitToDB(DownloadTask task) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
DownloadTask committed = dataManager.commit(task);
//return PersistenceHelper.isManaged(committed);
return committed != null;
}
private Terminal loadTerminalBySN(String terminalSN) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn)=:sn and t.deleteTs is null");
loadContext.getQuery().setParameter("sn", terminalSN.toLowerCase());
return dataManager.load(loadContext);
}
private DownloadTaskLog loadDownloadTaskLog(UUID logId) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<DownloadTaskLog> loadContext = LoadContext.create(DownloadTaskLog.class);
loadContext.setQueryString("select t from tms_DownloadTaskLog t where t.id=:id");
loadContext.getQuery().setParameter("id", logId);
loadContext.setView("downloadTaskLog-view");
return dataManager.load(loadContext);
}
private Integer getUnfinishedTask(UUID downloadTaskId) {
Double value = _getValueFromQuery("select count(*) from public.tms_download_task_log where task_id = '" + downloadTaskId.toString() + "' and activity not in (4,6,7);");
logger.debug("--> value: '" + value + "'");
return value != null ? value.intValue() : null;
}
private Double _getValueFromQuery(String query) {
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
Set<Double> numbers = runner.query(query,
new ResultSetHandler<Set<Double>>() {
@Nullable
@Override
public Set<Double> handle(ResultSet rs) throws SQLException {
Set<Double> rows = new HashSet<Double>();
while (rs.next()) {
rows.add(rs.getDouble(1));
}
return rows;
}
});
return numbers.isEmpty() ? null : numbers.toArray(new Double[] {})[0];
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,50 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
public class EchoListener implements IncomingMessageListener {
private Logger logger = LoggerFactory.getLogger(EchoListener.class);
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public EchoListener() {
}
@Override
public boolean incomingMessage(MqttConnector connector, String topic, String message) {
try {
String json = message;
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
logger.debug("Incoming MAP: " + map);
String type = (String) map.get("req_type");
if("ECHO".equals(type)) {
logger.debug("Detected Incoming: Echo ...");
UUID reqId = UUID.fromString((String) map.get("req_id"));
String _reqTime = (String) map.get("req_time");
reqId = UUID.randomUUID();
Date reqTime = dateTimeFormat.parse(_reqTime);
connector.echoReceived(reqTime);
return true;
} else {
// not my part
}
} catch(Exception ex) {
logger.error("Error handling incoming message: {}", ex.getMessage(), ex);
} finally {
}
return false;
}
}

View File

@ -0,0 +1,120 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.HeartBeat;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.enums.TerminalHeartBeatStatus;
import com.google.gson.Gson;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.security.app.Authentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
public class HeartBeatListener implements IncomingMessageListener {
private Logger logger = LoggerFactory.getLogger(HeartBeatListener.class);
private Authentication authentication;
public HeartBeatListener(Authentication authentication) {
this.authentication = authentication;
}
@Override
public boolean incomingMessage(MqttConnector connector, String topic, String message) {
try {
String json = message;
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
logger.debug("Incoming MAP: " + map);
logger.debug("Before Authentication ...");
authentication.begin();
logger.debug("Authenticated");
String type = (String) map.get("req_type");
if("HEARTBEAT".equals(type)) {
logger.debug("Detected Incoming: Heart Beat ...");
UUID reqId = UUID.fromString((String) map.get("req_id"));
reqId = UUID.randomUUID();
String terminalSN = (String) map.get("device_sn");
HeartBeat heartBeat = new HeartBeat();
heartBeat.setId(reqId);
heartBeat.setCreateTs(new Date());
heartBeat.setCreatedBy(terminalSN);
heartBeat.setVersion(1);
Terminal terminal = loadTerminalBySN(terminalSN);
if(terminal != null) {
// diagnostic info - mandatory
Map diagnosticInfoMap = (Map) map.get("diagnostic_info");
heartBeat.setTerminal(terminal);
heartBeat.setBatteryPercentage(getInt(diagnosticInfoMap, "battery_percentage"));
heartBeat.setBatteryTemp((Double) diagnosticInfoMap.get("battery_temp"));
// location info - mandatory
Map locationInfoMap = (Map) map.get("location_info");
heartBeat.setLatitude((Double) locationInfoMap.get("lat"));
heartBeat.setLongitude((Double) locationInfoMap.get("lng"));
boolean saved = commitToDB(heartBeat);
logger.debug("Save Heart Beat to DB: " + saved);
// set as ONLINE
terminal.setHeartBeatStatus(TerminalHeartBeatStatus.ONLINE);
terminal.setLastHeartBeatTime(new Date());
terminal.setLastHeartBeatId(heartBeat.getId());
boolean terminalSaved = commitToDB(terminal);
logger.debug("Save Terminal's Heart Beat to DB: " + terminalSaved);
} else {
logger.debug("Invalid Terminal: {}", terminalSN);
}
return true;
} else {
// not my part
}
} catch(Exception ex) {
logger.error("Error handling incoming message: {}", ex.getMessage(), ex);
} finally {
authentication.end();
}
return false;
}
private int getInt(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
return Integer.parseInt((String) val);
} else if(val instanceof Integer) {
return (Integer) val;
} else if(val instanceof Double) {
return ((Double) val).intValue();
}
return 0;
}
private boolean commitToDB(HeartBeat heartBeat) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
HeartBeat committed = dataManager.commit(heartBeat);
return PersistenceHelper.isManaged(committed);
}
private boolean commitToDB(Terminal terminal) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
Terminal committed = dataManager.commit(terminal);
return PersistenceHelper.isManaged(committed);
}
private Terminal loadTerminalBySN(String terminalSN) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn)=:sn and t.deleteTs is null");
loadContext.getQuery().setParameter("sn", terminalSN.toLowerCase());
return dataManager.load(loadContext);
}
}

View File

@ -0,0 +1,10 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
public interface IncomingMessageListener {
public boolean incomingMessage(MqttConnector connector, String topic, String message);
}

View File

@ -0,0 +1,296 @@
package com.cmobile.unifiedtms.core.mqtt.listener;
import com.cmobile.unifiedtms.core.config.FileDownloadConfig;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.*;
import com.cmobile.unifiedtms.entity.enums.DownloadTaskActivity;
import com.cmobile.unifiedtms.entity.enums.DownloadTimeType;
import com.cmobile.unifiedtms.entity.enums.InstallationTimeType;
import com.google.gson.Gson;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.app.LockService;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.security.app.Authentication;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class PendingTaskPushListener<LoginService> implements IncomingMessageListener {
private Logger logger = LoggerFactory.getLogger(PendingTaskPushListener.class);
private Authentication authentication;
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
private FileDownloadConfig fileDownloadConfig;
public PendingTaskPushListener(Authentication authentication) {
this.authentication = authentication;
}
public void setFileDownloadConfig(FileDownloadConfig fileDownloadConfig) {
this.fileDownloadConfig = fileDownloadConfig;
}
@Override
public boolean incomingMessage(MqttConnector connector, String topic, String message) {
try {
logger.debug("Listener Start ..");
String json = message;
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
logger.debug("Incoming MAP: " + map);
logger.debug("Before Authentication ...");
authentication.begin();
logger.debug("Authenticated");
String type = (String) map.get("req_type");
String terminalSN = (String) map.get("device_sn");
if(terminalSN != null) {
Terminal terminal = loadTerminalBySN(terminalSN);
if (terminal != null) {
List<DeleteTaskLog> deleteTaskLogs = getPendingDeleteTaskLogForTerminal(terminal);
List<DownloadTaskLog> downloadTaskLogs = getPendingDownloadTaskLogForTerminal(terminal);
logger.debug("Total Pending Delete Tasks: {}", deleteTaskLogs.size());
deleteTaskLogs.forEach(log -> {
try {
broadcastDeleteTasksToDevice(connector, log);
} catch (Exception ex) {
logger.error("Error Broadcast Delete Tasks: {}", ex.getMessage(), ex);
}
});
logger.debug("Total Pending Download Logs: {}", downloadTaskLogs.size());
downloadTaskLogs.forEach(log -> {
try {
broadcastDownloadTasksToDevice(connector, log);
} catch (Exception ex) {
logger.error("Error Broadcast Download Tasks: {}", ex.getMessage(), ex);
}
});
} else {
logger.debug("Invalid Terminal: {}", terminalSN);
}
}
} catch(Exception ex) {
logger.error("Error handling incoming message: {}", ex.getMessage(), ex);
} finally {
authentication.end();
logger.debug("Listener End ..");
}
return false;
}
// send download task to device topic via mqtt
public void broadcastDownloadTasksToDevice(MqttConnector mqttConnector,
DownloadTaskLog log) throws Exception {
DownloadTask task = log.getTask();
Terminal terminal = log.getTerminal();
Application app = log.getApplication();
Persistence persistence = AppBeans.get(Persistence.NAME);
DataManager dataManager = AppBeans.get(DataManager.NAME);
LockService lockService = AppBeans.get(LockService.NAME);
FileLoader fileLoader = AppBeans.get(FileLoader.NAME);
logger.debug("Broadcast tasks ...");
Transaction tx = persistence.createTransaction();
try {
// prepare commit context
CommitContext commitContext = new CommitContext();
try {
lockService.lock(log);
int qos = 2;
String topicName = terminal.getSn().toUpperCase() + "_IN";
// generate json
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
// we'll use log's id as ack_id
messageMap.put("ack_id", log.getId().toString());
messageMap.put("req_type", "DOWNLOAD_APP_TASK");
// task map
Map taskMap = new HashMap<>();
taskMap.put("id", task.getId().toString());
taskMap.put("name", task.getName());
taskMap.put("download_time_type", task.getDownloadTimeType().name());
if(task.getDownloadTimeType() == DownloadTimeType.DATETIME) {
taskMap.put("download_time", dateTimeFormat.format(task.getDownloadTime()));
}
taskMap.put("installation_time_type", task.getInstallationTimeType().name());
if(task.getInstallationTimeType() == InstallationTimeType.DATETIME) {
taskMap.put("installation_time", dateTimeFormat.format(task.getInstallationTime()));
}
taskMap.put("installation_notification", task.getInstallationNotification().name());
messageMap.put("task", taskMap);
// app map
Map appMap = new HashMap<>();
appMap.put("id", app.getId().toString());
appMap.put("name", app.getName());
appMap.put("package_name", app.getPackageName());
appMap.put("version", app.getAppVersion());
appMap.put("company", app.getCompanyName());
appMap.put("uninstallable", app.getUninstallable());
appMap.put("description", app.getDescription());
InputStream is = fileLoader.openStream(app.getApk());
String downloadURL = fileDownloadConfig.getFileDownloadURL();
if(downloadURL != null) {
downloadURL = downloadURL.replace("{$id}", app.getApk().getId().toString());
}
appMap.put("download_url", downloadURL);
appMap.put("md5_checksum", md5Checksum(is));
messageMap.put("app", appMap);
String messageData = gson.toJson(messageMap);
logger.debug("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.debug("Message published!");
// change log's last broadcast time
log.setLastBroadcastTs(new Date());
// add to commit context
commitContext.addInstanceToCommit(log);
} catch(Exception ex) {
logger.error("Error publish to device: {}", ex.getMessage(), ex);
} finally {
lockService.unlock(log);
}
dataManager.commit(commitContext);
tx.commit();
} finally {
logger.debug("Start broadcast download tasks DONE");
}
}
// send delete task to device topic via mqtt
public void broadcastDeleteTasksToDevice(MqttConnector mqttConnector,
DeleteTaskLog log) throws Exception {
DeleteTask task = log.getTask();
Terminal terminal = log.getTerminal();
ApplicationSimple app = log.getApplication();
Persistence persistence = AppBeans.get(Persistence.NAME);
DataManager dataManager = AppBeans.get(DataManager.NAME);
LockService lockService = AppBeans.get(LockService.NAME);
FileLoader fileLoader = AppBeans.get(FileLoader.NAME);
logger.debug("Broadcast tasks ...");
Transaction tx = persistence.createTransaction();
try {
// prepare commit context
CommitContext commitContext = new CommitContext();
try {
lockService.lock(log);
int qos = 2;
String topicName = terminal.getSn().toUpperCase() + "_IN";
// generate json
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
// we'll use log's id as ack_id
messageMap.put("ack_id", log.getId().toString());
messageMap.put("req_type", "DELETE_APP_TASK");
// task map
Map taskMap = new HashMap<>();
taskMap.put("id", task.getId().toString());
taskMap.put("name", task.getName());
taskMap.put("delete_time", task.getDeleteTime() != null ? dateTimeFormat.format(task.getDeleteTime()) : null);
messageMap.put("task", taskMap);
// app map
Map appMap = new HashMap<>();
appMap.put("id", app.getId().toString());
appMap.put("name", app.getAppName());
appMap.put("package_name", app.getPackageName());
messageMap.put("app", appMap);
String messageData = gson.toJson(messageMap);
logger.debug("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.debug("Message published!");
// change log's last broadcast time
log.setLastBroadcastTs(new Date());
// add to commit context
commitContext.addInstanceToCommit(log);
} catch(Exception ex) {
logger.error("Error publish to device: {}", ex.getMessage(), ex);
} finally {
lockService.unlock(log);
}
dataManager.commit(commitContext);
tx.commit();
} finally {
logger.debug("Start broadcast delete tasks DONE");
}
}
private String md5Checksum(InputStream is) throws Exception {
try {
String checksum = DigestUtils.md5Hex(is);
return checksum;
} finally {
if(is != null) {
is.close();
}
}
}
private int getInt(Map map, String key) {
Object val = map.get(key);
if(val instanceof String) {
return Integer.parseInt((String) val);
} else if(val instanceof Integer) {
return (Integer) val;
} else if(val instanceof Double) {
return ((Double) val).intValue();
}
return 0;
}
private boolean commitToDB(HeartBeat heartBeat) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
HeartBeat committed = dataManager.commit(heartBeat);
return PersistenceHelper.isManaged(committed);
}
private Terminal loadTerminalBySN(String terminalSN) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn)=:sn and t.deleteTs is null");
loadContext.getQuery().setParameter("sn", terminalSN.toLowerCase());
return dataManager.load(loadContext);
}
private List<DownloadTaskLog> getPendingDownloadTaskLogForTerminal(Terminal terminal) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<DownloadTaskLog> loadContext = LoadContext.create(DownloadTaskLog.class);
loadContext.setQueryString("select t from tms_DownloadTaskLog t where t.terminal.id=:terminalId and t.activity=:activity order by t.createTs desc");
loadContext.getQuery().setParameter("terminalId", terminal.getId());
loadContext.getQuery().setParameter("activity", DownloadTaskActivity.INITIAL);
loadContext.setView("downloadTaskLog-with-task-view");
return dataManager.loadList(loadContext);
}
private List<DeleteTaskLog> getPendingDeleteTaskLogForTerminal(Terminal terminal) {
DataManager dataManager = AppBeans.get(DataManager.NAME);
LoadContext<DeleteTaskLog> loadContext = LoadContext.create(DeleteTaskLog.class);
loadContext.setQueryString("select t from tms_DeleteTaskLog t where t.terminal.id=:terminalId and t.activity=:activity order by t.createTs desc");
loadContext.getQuery().setParameter("terminalId", terminal.getId());
loadContext.getQuery().setParameter("activity", DownloadTaskActivity.INITIAL);
loadContext.setView("deleteTaskLog-with-task-view");
return dataManager.loadList(loadContext);
}
}

View File

@ -0,0 +1,65 @@
package com.cmobile.unifiedtms.core.security;
import com.haulmont.cuba.core.global.Messages;
import com.haulmont.cuba.security.app.UserSessionsAPI;
import com.haulmont.cuba.security.auth.AbstractClientCredentials;
import com.haulmont.cuba.security.auth.events.BeforeLoginEvent;
import com.haulmont.cuba.security.global.LoginException;
import org.slf4j.Logger;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.Locale;
import java.util.Objects;
@Component
public class MyLoginEventListener {
@Inject
private UserSessionsAPI userSessions;
@Inject
private Messages messages;
@Inject
private Logger logger;
@EventListener
private void onBeforeLogin(BeforeLoginEvent event) throws LoginException {
if (event.getCredentials() instanceof AbstractClientCredentials) {
String login = ((AbstractClientCredentials) event.getCredentials()).getUserIdentifier();
if(login.contains("rest")) return;
Locale locale = ((AbstractClientCredentials) event.getCredentials()).getLocale();
/*if (checkConcurrentUsers(login))
throw new LoginException(messages.getMessage(getClass(), "LoginException.concurrentUsersLimitExceeded", locale));
*/
abortOtherLogins(login);
}
}
/**
* @return true if user limit is not exceeded
*/
protected boolean checkConcurrentUsers(String login) {
/*logger.info("Logged in users");
userSessions.getUserSessionsStream()
.forEach(userSession -> {
logger.info("Logged in: " + userSession.getUser().getLogin());
});
logger.info("End of Logged in users");
*/
return userSessions.getUserSessionsStream()
.anyMatch(s -> !s.isSystem() && Objects.equals(s.getUser().getLogin(), login));
}
protected void abortOtherLogins(String login) {
userSessions.getUserSessionsStream()
.forEach(userSession -> {
String userLogin = userSession.getUser().getLogin();
if(login.equalsIgnoreCase(userLogin)) {
userSessions.killSession(userSession.getId());
logger.info("Kill session id: " + userSession.getId() + " for user: " + userSession.getUser().getLogin());
}
});
}
}

View File

@ -0,0 +1,49 @@
package com.cmobile.unifiedtms.core.security;
import com.cmobile.unifiedtms.security.UserSessionExistsException;
import com.haulmont.cuba.security.app.UserSessionsAPI;
import com.haulmont.cuba.security.auth.AbstractClientCredentials;
import com.haulmont.cuba.security.auth.AuthenticationDetails;
import com.haulmont.cuba.security.auth.Credentials;
import com.haulmont.cuba.security.auth.UserAccessChecker;
import com.haulmont.cuba.security.global.LoginException;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.Objects;
@Component(UserSessionExistsAccessChecker.NAME)
public class UserSessionExistsAccessChecker implements UserAccessChecker, Ordered {
public static final String NAME = "scm_UserSessionExistsAccessChecker";
@Inject
protected UserSessionsAPI userSessions;
@Override
public void check(Credentials credentials, AuthenticationDetails authenticationDetails) throws LoginException {
if (credentials instanceof AbstractClientCredentials) {
AbstractClientCredentials clientCredentials = (AbstractClientCredentials) credentials;
if(clientCredentials.getUserIdentifier().contains("rest")) return;
if (clientCredentials.getParams() != null && Boolean.TRUE.equals(clientCredentials.getParams().get("abortSession"))) {
userSessions.getUserSessionsStream()
.filter(s -> !s.isSystem() && Objects.equals(s.getUser().getLogin(), clientCredentials.getUserIdentifier()))
.findAny()
.ifPresent(s -> userSessions.killSession(s.getId()));
}
if (checkExistsUser(clientCredentials.getUserIdentifier()))
throw new UserSessionExistsException(clientCredentials.getUserIdentifier());
}
}
protected boolean checkExistsUser(String login) {
return userSessions.getUserSessionsStream()
.anyMatch(s -> !s.isSystem() && Objects.equals(s.getUser().getLogin(), login));
}
@Override
public int getOrder() {
return HIGHEST_PLATFORM_PRECEDENCE;
}
}

View File

@ -0,0 +1 @@
LoginException.concurrentUsersLimitExceeded = User already logged in!!

View File

@ -0,0 +1 @@
LoginException.concurrentUsersLimitExceeded = Pengguna sudah login!!

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<fts-config xmlns="http://schemas.haulmont.com/cuba/fts.xsd">
<entities>
<entity class="com.cmobile.unifiedtms.entity.HeartBeat">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.DiagnosticInfo">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.DownloadTask">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.DownloadTaskLog">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.TerminalLastHeartBeat">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.TerminalLastDiagnosticInfo">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.ApplicationSimple">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.DeleteTaskLog">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.TerminalLink">
<include re=".*"/>
</entity>
<entity class="com.cmobile.unifiedtms.entity.TerminalReport">
<include re=".*"/>
</entity>
</entities>
</fts-config>

View File

@ -0,0 +1,69 @@
package com.cmobile.unifiedtms.listeners;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.Events;
import com.haulmont.cuba.core.sys.events.AppContextInitializedEvent;
import com.haulmont.cuba.core.sys.events.AppContextStartedEvent;
import com.haulmont.cuba.core.sys.events.AppContextStoppedEvent;
import com.haulmont.cuba.core.sys.servlet.events.ServletContextDestroyedEvent;
import com.haulmont.cuba.core.sys.servlet.events.ServletContextInitializedEvent;
import java.io.File;
import org.slf4j.Logger;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.license4j.util.FileUtils;
import javax.inject.Inject;
@Component("tms_AppLifecycleEventListener_ApplicationContextListener")
public class AppLifecycleEventListener {
@Inject
private Logger log;
@EventListener
@Order(Events.LOWEST_PLATFORM_PRECEDENCE + 100)
public void applicationContextInitialized(AppContextInitializedEvent event) {
log.info("Application context is Initialized");
MqttConnector mqttConnector = AppBeans.get(MqttConnector.NAME);
// validate license
validateLicense();
}
private void validateLicense() throws RuntimeException {
/*
String appHome = System.getProperty("app.home");
String licenseFile = appHome + File.separator + "license.l4j";
try {
String licenseString = FileUtils.readFile("D:\\Documents\\Personal\\Verifone\\UTMS\\Licenses\\1626785999496.l4j");
String publickey = "30820122300d06092a864886f70d01010105000382010f00303032301006072a8648ce3d02002EC311215SHA512withECDSA106052b81040006031e0004125ca10acdc54807553b11bb9b4f59fe947f68788fe9e6f0d324a03bG82010a0282010100859c388d100cacf014e7f61be9d30f5c262feadf8440affe93a85021e212a808ff6aa40e2d318ef6b298f61a68fc8bde2237fbd9241988fb7a6fe07138bab8ace340e907213daaeb7121747c5f022bd7ee5f49d49dba64883fa0674403RSA4204813SHA512withRSA7672242c571f7edb5966469150d9240464c64087727561c8cc40609b8ff0ea7e07bd08d643f6c04ef3c860092354be465bb3136cb517b0cbb5f5718f8fd95e95a33b848f01cec185afbb43062af5c8ff7f2030783371b6dbbd4f7230b1725b4dc846d1a40d7b38d369ee6df56d8a8648858b5f5b6aac61c12698dfac749bd112443bec8b9bc13e9c405053200789664afee8ed6b7dd52b264f1f58e6843bd18ae5eab76b0203010001";
String productID = "utms";
String productEdition = "Production";
String productVersion = "1.0";
} finally {}
*/
}
@EventListener
public void applicationContextStarted(AppContextStartedEvent event) {
log.info("Application context is Started");
}
@EventListener
public void applicationContextStopped(AppContextStoppedEvent event) {
log.info("Application context is Stopped");
}
@EventListener
public void servletContextInitializedEvent(ServletContextInitializedEvent event) {
log.info("Application and servlet context is initialized");
}
@EventListener
public void servletContextDestroyedEvent(ServletContextDestroyedEvent event) {
log.info("Application is about to shut down, all contexts are now destroyed");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
package com.cmobile.unifiedtms.service;
import com.pras.Extract;
import com.pras.Manifest;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@Service(ApkService.NAME)
public class ApkServiceBean implements ApkService {
@Override
public Manifest extractManifest(byte[] bytes) throws Exception {
InputStream in = null;
try {
in = new ByteArrayInputStream(bytes);
Extract extract = new Extract();
Manifest manifest = extract.extractManifest(in);
return manifest;
} finally {
if(in != null) {
try {
in.close();
} catch(IOException ignore) {}
in = null;
}
}
}
}

View File

@ -0,0 +1,96 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.entity.chartdata.PieChartData;
import com.haulmont.addon.sdbmt.core.app.multitenancy.TenantProvider;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.*;
@Service(ChartDataService.NAME)
public class ChartDataServiceBean implements ChartDataService {
private Logger logger = LoggerFactory.getLogger(ChartDataServiceBean.class);
@Inject
private Persistence persistence;
@Inject
private TenantProvider tenantProvider;
@Override
public List<PieChartData> getDownloadStats() {
String tenantId = tenantProvider.getCurrentUserTenantId();
String query;
String[] params = new String[] {};
int[] types = new int[] {};
if(tenantId == null || "no_tenant".equals(tenantId)) {
query = ""
+ "select task.id, task.name, "
+ " sum(case when log.activity=1 then 1 else 0 end) total_not_downloaded, "
+ " sum(case when log.activity=3 then 1 else 0 end) total_downloaded, "
+ " sum(case when log.activity=5 then 1 else 0 end) total_tobe_installed, "
+ " sum(case when log.activity=6 then 1 else 0 end) total_installed "
+ "from tms_download_task task "
+ " left join tms_download_task_log log on log.task_id=task.id "
+ "where task.delete_ts is null "
+ "group by task.id,task.name,task.create_ts "
+ "order by task.create_ts desc "
+ "limit 2";
} else {
params = new String[] { tenantId };
types = new int[] { Types.VARCHAR };
query = ""
+ "select task.id, task.name, "
+ " sum(case when log.activity=1 then 1 else 0 end) total_not_downloaded, "
+ " sum(case when log.activity=3 then 1 else 0 end) total_downloaded, "
+ " sum(case when log.activity=5 then 1 else 0 end) total_tobe_installed, "
+ " sum(case when log.activity=6 then 1 else 0 end) total_installed "
+ "from tms_download_task task "
+ " left join tms_download_task_log log on log.task_id=task.id "
+ "where task.tenant_id=? and task.delete_ts is null "
+ "group by task.id,task.name,task.create_ts "
+ "order by task.create_ts desc "
+ "limit 2";
}
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
Set<PieChartData> datas = runner.query(query,
params,
types,
new ResultSetHandler<Set<PieChartData>>() {
@Nullable
@Override
public Set<PieChartData> handle(ResultSet rs) throws SQLException {
Set<PieChartData> rows = new HashSet<PieChartData>();
while (rs.next()) {
String id = rs.getString(1);
String name = rs.getString(2);
int notDownloaded = rs.getInt(3);
int downloaded = rs.getInt(4);
int tobeInstalled = rs.getInt(5);
int installed = rs.getInt(6);
PieChartData data = new PieChartData(id, name);
data.addValue("Not Downloaded", notDownloaded);
data.addValue("Downloaded", downloaded);
data.addValue("To be Installed", tobeInstalled);
data.addValue("Installed", installed);
rows.add(data);
}
return rows;
}
});
return new ArrayList<>(datas);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,226 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.*;
import com.cmobile.unifiedtms.entity.enums.*;
import com.google.gson.Gson;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.app.LockService;
import com.haulmont.cuba.core.global.*;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Service(DeleteTaskService.NAME)
public class DeleteTaskServiceBean implements DeleteTaskService {
@Inject
private Logger logger;
@Inject
private DataManager dataManager;
@Inject
private Persistence persistence;
@Inject
private LockService lockService;
@Inject
private Metadata metadata;
@Inject
private MqttConnector mqttConnector;
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Override
public void startDeleteTasks() throws Exception {
logger.info("Start delete tasks ...");
Transaction tx = persistence.createTransaction();
try {
// load all NOT_STARTED download tasks
LoadContext<DeleteTask> loadContext = LoadContext.create(DeleteTask.class);
loadContext.setQueryString("select t from tms_DeleteTask t where t.deleteTs is null and t.status=:status");
loadContext.getQuery().setParameter("status", TaskStatus.NOT_STARTED);
loadContext.setView("deleteTask-view");
List<DeleteTask> tasks = dataManager.loadList(loadContext);
logger.info("Total tasks: {}", tasks.size());
// prepare commit context
CommitContext commitContext = new CommitContext();
tasks.forEach(task -> {
try {
lockService.lock(task);
// get the apps
List<ApplicationSimple> applications = task.getApplications();
// get the terminals
List<TerminalGroup> terminalGroups = task.getTerminalGroups();
List<Terminal> terminals = new ArrayList<>();
terminalGroups.forEach(terminalGroup -> {
List<Terminal> _terminals = terminalGroup.getTerminals();
_terminals.forEach(terminal -> {
if(!terminals.contains(terminal)) {
terminals.add(terminal);
}
});
});
// create the delete log for each app - terminal
terminals.forEach(terminal -> {
applications.forEach(app -> {
DeleteTaskLog log = metadata.create(DeleteTaskLog.class);
log.setApplication(app);
log.setTerminal(terminal);
log.setTask(task);
log.setActivity(DeleteTaskActivity.INITIAL);
// add to commit context
commitContext.addInstanceToCommit(log);
});
});
// change task's status to IN_PROGRESS
task.setStatus(TaskStatus.IN_PROGRESS);
// add to commit context
commitContext.addInstanceToCommit(task);
} finally {
lockService.unlock(task);
}
});
dataManager.commit(commitContext);
tx.commit();
} finally {
logger.info("Start delete tasks DONE");
}
}
// send to device topic via mqtt
public void broadcastTasksToDevices() throws Exception {
logger.info("Broadcast tasks ...");
Transaction tx = persistence.createTransaction();
try {
// load all INITIAL logs
LoadContext<DeleteTaskLog> loadContext = LoadContext.create(DeleteTaskLog.class);
loadContext.setQueryString("select t from tms_DeleteTaskLog t where t.activity=:activity");
loadContext.getQuery().setParameter("activity", DownloadTaskActivity.INITIAL);
loadContext.setView("deleteTaskLog-view");
List<DeleteTaskLog> logs = dataManager.loadList(loadContext);
logger.info("Total logs: {}", logs.size());
// prepare commit context
CommitContext commitContext = new CommitContext();
logs.forEach(log -> {
try {
// check last
Date lastBroadcastTime = log.getLastBroadcastTs();
if(lastBroadcastTime != null) {
// check if less then 15 minutes
long TEN_MINUTES = TimeUnit.MINUTES.toMillis(10);
long elapsed = System.currentTimeMillis() - lastBroadcastTime.getTime();
if(elapsed < TEN_MINUTES) {
logger.info("Skipping coz < 10 minutes for SN: {}", log.getTerminal().getSn());
return;
}
}
lockService.lock(log);
// terminal
Terminal terminal = log.getTerminal();
ApplicationSimple app = log.getApplication();
DeleteTask task = log.getTask();
int qos = 2;
String topicName = terminal.getSn().toUpperCase() + "_IN";
// generate json
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
// we'll use log's id as ack_id
messageMap.put("ack_id", log.getId().toString());
messageMap.put("req_type", "DELETE_APP_TASK");
// task map
Map taskMap = new HashMap<>();
taskMap.put("id", task.getId().toString());
taskMap.put("name", task.getName());
taskMap.put("delete_time", task.getDeleteTime() != null ? dateTimeFormat.format(task.getDeleteTime()) : null);
messageMap.put("task", taskMap);
// app map
Map appMap = new HashMap<>();
appMap.put("id", app.getId().toString());
appMap.put("name", app.getAppName());
appMap.put("package_name", app.getPackageName());
messageMap.put("app", appMap);
String messageData = gson.toJson(messageMap);
logger.info("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.info("Message published!");
// change log's last broadcast time
log.setLastBroadcastTs(new Date());
// add to commit context
commitContext.addInstanceToCommit(log);
} catch(Exception ex) {
logger.error("Error publish to device: {}", ex.getMessage(), ex);
} finally {
lockService.unlock(log);
}
});
dataManager.commit(commitContext);
tx.commit();
} finally {
logger.info("Start broadcast delete tasks DONE");
}
}
@Override
public String updateTaskStatuses() throws Exception {
String query = "select datas.arr[0] status,datas.arr[1] message from ("
+ "select update_delete_task_status() arr "
+ ") datas";
String[] params = new String[] {
};
logger.info("update_delete_task_status()");
int[] types = new int[] {
};
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
String[] datas = runner.query(query,
params,
types,
new ResultSetHandler<String[]>() {
@Nullable
@Override
public String[] handle(ResultSet rs) throws SQLException {
if(rs.next()) {
String[] ret = new String[2];
ret[0] = rs.getString(1);
ret[1] = rs.getString(2);
return ret;
}
return null;
}
});
StringBuilder sb = new StringBuilder();
if(datas != null) {
sb.append("[").append(datas[0]).append(", ").append(datas[1]).append("]");
}
return sb.toString();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,130 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.MqttConfig;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.DeviceProfile;
import com.cmobile.unifiedtms.entity.DeviceProfileApp;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.TerminalGroup;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.text.SimpleDateFormat;
import java.util.*;
@Service(DeviceInitService.NAME)
public class DeviceInitServiceBean implements DeviceInitService {
@Inject
private MqttConfig mqttConfig;
@Inject
private MqttConnector connector;
private Logger logger = LoggerFactory.getLogger(DeviceInitServiceBean.class);
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
@Override
public void publishInit(DeviceProfile profile, Terminal terminal) {
try {
int qos = 2;
String topicName = terminal.getSn().toUpperCase() + "_IN";
// generate json
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
messageMap.put("req_type", "UPDATE_PROFILE");
// profile map
Map profileMap = new HashMap<>();
profileMap.put("id", profile.getId().toString());
profileMap.put("name", profile.getName());
profileMap.put("hearbeat_interval", profile.getHeartbeatInterval());
profileMap.put("diagnostic_interval", profile.getDiagnosticInterval());
profileMap.put("mask_home_button", profile.getMaskHomeButton());
profileMap.put("mask_status_button", profile.getMaskStatusBar());
profileMap.put("schedule_reboot", profile.getScheduleReboot());
if(profile.getScheduleReboot()) {
profileMap.put("schedule_reboot_time", timeFormat.format(profile.getScheduleRebootTime()));
}
profileMap.put("relocation_alert", profile.getRelocationAlert());
profileMap.put("moving_threshold", profile.getMovingThreshold());
profileMap.put("admin_password", profile.getAdminPassword());
// mqtt host
profileMap.put("host", mqttConfig.getDeviceHost());
// additional
profileMap.put("front_app", profile.getFrontApp());
List<DeviceProfileApp> apps = profile.getApps();
List<String> appList = new ArrayList<>();
for(DeviceProfileApp app : apps) {
appList.add(app.getPackageName());
}
profileMap.put("apps_home_list", appList);
messageMap.put("profile", profileMap);
Gson gson = new Gson();
String messageData = gson.toJson(messageMap);
logger.info("Try publish message to: {}", topicName);
connector.publishRetainedMessage(topicName, messageData, qos);
//connector.publishMessage(topicName, messageData, qos);
logger.info("Message published!");
} catch(Exception ex) {
throw new RuntimeException(ex);
}
}
@Override
public void publishInitToProfile(DeviceProfile profile) {
try {
int qos = 2;
String topicName = profile.getId().toString();
// generate json
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
messageMap.put("req_type", "UPDATE_PROFILE");
// profile map
Map profileMap = new HashMap<>();
profileMap.put("id", profile.getId().toString());
profileMap.put("name", profile.getName());
profileMap.put("hearbeat_interval", profile.getHeartbeatInterval());
profileMap.put("diagnostic_interval", profile.getDiagnosticInterval());
profileMap.put("mask_home_button", profile.getMaskHomeButton());
profileMap.put("mask_status_button", profile.getMaskStatusBar());
profileMap.put("schedule_reboot", profile.getScheduleReboot());
if(profile.getScheduleReboot()) {
profileMap.put("schedule_reboot_time", timeFormat.format(profile.getScheduleRebootTime()));
}
profileMap.put("relocation_alert", profile.getRelocationAlert());
profileMap.put("moving_threshold", profile.getMovingThreshold());
profileMap.put("admin_password", profile.getAdminPassword());
// mqtt host
profileMap.put("host", mqttConfig.getDeviceHost());
// additional
profileMap.put("front_app", profile.getFrontApp());
List<DeviceProfileApp> apps = profile.getApps();
List<String> appList = new ArrayList<>();
for(DeviceProfileApp app : apps) {
appList.add(app.getPackageName());
}
profileMap.put("apps_home_list", appList);
messageMap.put("profile", profileMap);
Gson gson = new Gson();
String messageData = gson.toJson(messageMap);
logger.info("Try publish message to: {}", topicName);
connector.publishRetainedMessage(topicName, messageData, qos);
//connector.publishMessage(topicName, messageData, qos);
logger.info("Message published!");
} catch(Exception ex) {
throw new RuntimeException(ex);
}
}
}

View File

@ -0,0 +1,335 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.config.BroadcastConfig;
import com.cmobile.unifiedtms.core.config.ExtendedConfig;
import com.cmobile.unifiedtms.core.config.FileDownloadConfig;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.cmobile.unifiedtms.entity.*;
import com.cmobile.unifiedtms.entity.enums.*;
import com.google.gson.Gson;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.app.LockService;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Service(DownloadTaskService.NAME)
public class DownloadTaskServiceBean implements DownloadTaskService {
@Inject
private Logger logger;
@Inject
private DataManager dataManager;
@Inject
private Persistence persistence;
@Inject
private LockService lockService;
@Inject
private Metadata metadata;
@Inject
private MqttConnector mqttConnector;
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
@Inject
private FileLoader fileLoader;
@Inject
private FileDownloadConfig fileDownloadConfig;
@Inject
private BroadcastConfig broadcastConfig;
@Inject
private ExtendedConfig extendedConfig;
@Override
public void startDownloadTasks() throws Exception {
logger.info("Start download tasks ...");
Transaction tx = persistence.createTransaction();
try {
// load all NOT_STARTED download tasks
LoadContext<DownloadTask> loadContext = LoadContext.create(DownloadTask.class);
loadContext.setQueryString("select t from tms_DownloadTask t where t.deleteTs is null and t.status=:status");
loadContext.getQuery().setParameter("status", TaskStatus.NOT_STARTED);
loadContext.setView("downloadTask-view");
List<DownloadTask> tasks = dataManager.loadList(loadContext);
logger.info("Total tasks: {}", tasks.size());
// prepare commit context
CommitContext commitContext = new CommitContext();
tasks.forEach(task -> {
try {
lockService.lock(task);
boolean containBlackListed = false;
String whitelistPackageNames = extendedConfig.getWhitelistPackageNames();
int blacklistThreshold = extendedConfig.getBlacklistThreshold();
logger.info("Whitelist package names: {}", whitelistPackageNames);
logger.info("Blacklist threshold: {}", blacklistThreshold);
// get the apps
List<Application> applications = task.getApplications();
for(Application app : applications) {
boolean whiteListed = app.getPackageName().matches(whitelistPackageNames);
logger.info("Checking '{}' : {}", app.getPackageName(), whiteListed);
containBlackListed |= !whiteListed;
}
// get the terminals
List<TerminalGroup> terminalGroups = task.getTerminalGroups();
List<Terminal> terminals = new ArrayList<>();
terminalGroups.forEach(terminalGroup -> {
List<Terminal> _terminals = terminalGroup.getTerminals();
_terminals.forEach(terminal -> {
if(!terminals.contains(terminal)) {
terminals.add(terminal);
}
});
});
int totalTerminal = terminals.size();
boolean continueStart = !containBlackListed || (totalTerminal <= blacklistThreshold);
logger.info("Contain blacklisted : {}, Total Terminal: {} => Continue start: {}", containBlackListed, totalTerminal, continueStart);
if(continueStart) {
// create the download log for each app - terminal
terminals.forEach(terminal -> {
applications.forEach(app -> {
DownloadTaskLog log = metadata.create(DownloadTaskLog.class);
log.setApplication(app);
log.setTerminal(terminal);
log.setTask(task);
log.setActivity(DownloadTaskActivity.INITIAL);
// add to commit context
commitContext.addInstanceToCommit(log);
});
});
// change task's status to IN_PROGRESS
task.setStatus(TaskStatus.IN_PROGRESS);
// add to commit context
commitContext.addInstanceToCommit(task);
} else {
logger.info("Task contain package not in whitelist and total terminal > {}", blacklistThreshold);
// cancel task directly
// change task's status to CANCELED
task.setStatus(TaskStatus.CANCELLED);
// add to commit context
commitContext.addInstanceToCommit(task);
}
} finally {
lockService.unlock(task);
}
});
dataManager.commit(commitContext);
tx.commit();
} finally {
logger.info("Start download tasks DONE");
}
}
// send to device topic via mqtt
public void broadcastTasksToDevices() throws Exception {
logger.info("Broadcast tasks ...");
Transaction tx = persistence.createTransaction();
try {
// load all INITIAL logs
LoadContext<DownloadTaskLog> loadContext = LoadContext.create(DownloadTaskLog.class);
loadContext.setQueryString("select t from tms_DownloadTaskLog t where t.activity=:activity");
loadContext.getQuery().setParameter("activity", DownloadTaskActivity.INITIAL);
loadContext.setView("downloadTaskLog-view");
List<DownloadTaskLog> logs = dataManager.loadList(loadContext);
logger.info("Total logs: {}", logs.size());
// prepare commit context
CommitContext commitContext = new CommitContext();
logs.forEach(log -> {
try {
// check last
Date lastBroadcastTime = log.getLastBroadcastTs();
if(lastBroadcastTime != null) {
// check if less then 15 minutes
long TEN_MINUTES = TimeUnit.MINUTES.toMillis(10);
long elapsed = System.currentTimeMillis() - lastBroadcastTime.getTime();
if(elapsed < TEN_MINUTES) {
logger.info("Skipping coz < 10 minutes for SN: {}", log.getTerminal().getSn());
return;
}
}
lockService.lock(log);
// terminal
Terminal terminal = log.getTerminal();
Application app = log.getApplication();
DownloadTask task = log.getTask();
int qos = 2;
String topicName = terminal.getSn().toUpperCase() + "_IN";
// generate json
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
// we'll use log's id as ack_id
messageMap.put("ack_id", log.getId().toString());
messageMap.put("req_type", "DOWNLOAD_APP_TASK");
// task map
Map taskMap = new HashMap<>();
taskMap.put("id", task.getId().toString());
taskMap.put("name", task.getName());
taskMap.put("download_time_type", task.getDownloadTimeType().name());
if(task.getDownloadTimeType() == DownloadTimeType.DATETIME) {
taskMap.put("download_time", dateTimeFormat.format(task.getDownloadTime()));
}
taskMap.put("installation_time_type", task.getInstallationTimeType().name());
if(task.getInstallationTimeType() == InstallationTimeType.DATETIME) {
taskMap.put("installation_time", dateTimeFormat.format(task.getInstallationTime()));
}
taskMap.put("installation_notification", task.getInstallationNotification().name());
messageMap.put("task", taskMap);
// app map
Map appMap = new HashMap<>();
appMap.put("id", app.getId().toString());
appMap.put("name", app.getName());
appMap.put("package_name", app.getPackageName());
appMap.put("version", app.getAppVersion());
appMap.put("company", app.getCompanyName());
appMap.put("uninstallable", app.getUninstallable());
appMap.put("description", app.getDescription());
InputStream is = fileLoader.openStream(app.getApk());
String downloadURL = fileDownloadConfig.getFileDownloadURL();
if(downloadURL != null) {
downloadURL = downloadURL.replace("{$id}", app.getApk().getId().toString());
}
appMap.put("download_url", downloadURL);
appMap.put("md5_checksum", md5Checksum(is));
messageMap.put("app", appMap);
String messageData = gson.toJson(messageMap);
logger.info("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.info("Message published!");
// change log's last broadcast time
log.setLastBroadcastTs(new Date());
// add to commit context
commitContext.addInstanceToCommit(log);
} catch(Exception ex) {
logger.error("Error publish to device: {}", ex.getMessage(), ex);
} finally {
lockService.unlock(log);
}
});
dataManager.commit(commitContext);
tx.commit();
} finally {
logger.info("Start broadcast download tasks DONE");
}
}
@Override
public String updateTaskStatuses() throws Exception {
String query = "select datas.arr[0] status,datas.arr[1] message from ("
+ "select update_download_task_status() arr "
+ ") datas";
String[] params = new String[] {
};
logger.info("update_download_task_status()");
int[] types = new int[] {
};
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
String[] datas = runner.query(query,
params,
types,
new ResultSetHandler<String[]>() {
@Nullable
@Override
public String[] handle(ResultSet rs) throws SQLException {
if(rs.next()) {
String[] ret = new String[2];
ret[0] = rs.getString(1);
ret[1] = rs.getString(2);
return ret;
}
return null;
}
});
StringBuilder sb = new StringBuilder();
if(datas != null) {
sb.append("[").append(datas[0]).append(", ").append(datas[1]).append("]");
}
return sb.toString();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void broadcastChangeProfileTaskToDevices() throws Exception {
logger.info("Broadcast Change Profile task ...");
try {
int qos = 2;
String topicName = "SERVER_OUT";
// generate json
String reqId = broadcastConfig.getChangeProfileReqId();
if(reqId == null) {
reqId = UUID.randomUUID().toString();
broadcastConfig.setChangeProfileReqId(reqId);
}
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", reqId);
messageMap.put("req_time", dateTimeFormat.format(new Date()));
messageMap.put("req_type", "CHANGE_PROFILE");
String messageData = gson.toJson(messageMap);
logger.info("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.info("Message published!");
} finally {
logger.info("Broadcast Change Profile task DONE");
}
}
private String md5Checksum(InputStream is) throws Exception {
try {
String checksum = DigestUtils.md5Hex(is);
return checksum;
} finally {
if(is != null) {
is.close();
}
}
}
}

View File

@ -0,0 +1,51 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.core.mqtt.MqttConnector;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Service(EchoService.NAME)
public class EchoServiceBean implements EchoService {
@Inject
private Logger logger;
@Inject
private MqttConnector mqttConnector;
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// send to device topic via mqtt
public void sendEcho() throws Exception {
logger.info("Broadcast echo ...");
try {
int qos = 2;
// self echo to SERVER_IN
String topicName = "SERVER_IN";
// generate json
Gson gson = new Gson();
Map messageMap = new HashMap<>();
messageMap.put("req_id", UUID.randomUUID().toString());
messageMap.put("req_time", dateTimeFormat.format(new Date()));
messageMap.put("req_type", "ECHO");
String messageData = gson.toJson(messageMap);
logger.info("Try publish message to: {}", topicName);
//mqttConnector.publishRetainedMessage(topicName, messageData, qos);
mqttConnector.publishMessage(topicName, messageData, qos);
logger.info("Message published!");
} catch(Exception ex) {
logger.error("Error publish to device: {}", ex.getMessage(), ex);
} finally {
logger.info("Start broadcast echo task DONE");
}
}
}

View File

@ -0,0 +1,248 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.entity.misc.FileDownloadWrapper;
import com.google.gson.Gson;
import com.haulmont.cuba.core.app.FileStorageService;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.security.app.Authentication;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import javax.inject.Inject;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@Service(FileService.NAME)
public class FileServiceBean implements FileService {
@Inject
private Logger logger;
@Inject
private DataManager dataManager;
@Inject
private FileStorageService fileStorageService;
@Inject
private FileLoader fileLoader;
private Authentication authentication;
@Override
public void downloadFile(@PathVariable String fileDescriptorId,
HttpServletResponse response) {
try {
authentication.begin();
UUID fileId = UUID.fromString(fileDescriptorId);
LoadContext<FileDescriptor> loadContext = LoadContext.create(FileDescriptor.class);
loadContext.setId(fileId);
FileDescriptor fd = dataManager.load(loadContext);
byte[] bytes = fileStorageService.loadFile(fd);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Content-Type", getContentType(fd));
response.setHeader("Content-Disposition", "attachment" + "; filename=\"" + fd.getName() + "\"");
downloadFromMiddlewareAndWriteResponse(fd, response);
} catch(Exception ex) {
throw new RuntimeException(ex);
} finally {
authentication.end();
}
}
@Override
public FileDownloadWrapper uploadFileToRemote(FileDescriptor fd) {
try {
return uploadFile(fd);
} catch(Exception ex) {
throw new RuntimeException(ex);
} finally {
}
}
@Override
public FileDownloadWrapper uploadFileToRemote(FileDescriptor fd, boolean useFilename) {
try {
return uploadFile(fd, useFilename);
} catch(Exception ex) {
throw new RuntimeException(ex);
} finally {
}
}
protected void downloadFromMiddlewareAndWriteResponse(FileDescriptor fd, HttpServletResponse response) throws IOException {
ServletOutputStream os = response.getOutputStream();
try (InputStream is = fileLoader.openStream(fd)) {
IOUtils.copy(is, os);
os.flush();
} catch (FileStorageException e) {
throw new IOException("Unable to download file from FileStorage: " + fd.getId(), e);
}
}
protected String getContentType(FileDescriptor fd) {
if (StringUtils.isEmpty(fd.getExtension())) {
return FileTypesHelper.DEFAULT_MIME_TYPE;
}
return FileTypesHelper.getMIMEType("." + fd.getExtension().toLowerCase());
}
public FileDownloadWrapper uploadFile(FileDescriptor fd, boolean useFilename) throws Exception {
try {
int connectTimeout = 10;
int timeout = 30;
FileDownloadWrapper fdWrapper = new FileDownloadWrapper();
fdWrapper.setUploaded(false);
byte[] bytes = fileStorageService.loadFile(fd);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
// get md5 checksum
String md5Checksum = md5Checksum(bais);
String url = "http://filedownload.unifiedtms.id:7177/apiEDC";
RequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout * 1000).setConnectionRequestTimeout(connectTimeout * 1000).setSocketTimeout(timeout * 1000).build();
CloseableHttpClient httpclient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
HttpPost httpPost = new HttpPost(url);
String filename = fd.getId()+"."+fd.getExtension();
if(useFilename) {
filename = fd.getName();
}
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody
("document", bytes, ContentType.DEFAULT_BINARY, filename);
builder.addTextBody("command", "upload-file-to-minio");
HttpEntity reqEntity = builder.build();
httpPost.setEntity(reqEntity);
logger.info(">>> Upload file: {}", filename);
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != 200) {
throw new RuntimeException("HTTP Status Not 200 (OK) : " + statusLine.getStatusCode() + " - " + statusLine.getReasonPhrase());
} else {
HttpEntity entity = response.getEntity();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
entity.writeTo(baos);
String jsonResponse = new String(baos.toByteArray());
logger.info("<<< {}", jsonResponse);
Gson gson = new Gson();
Map responseMap = gson.fromJson(jsonResponse, Map.class);
Double status = (Double) responseMap.get("status");
if (status == 200) {
// get file
String downloadUrl = getFiledownloadUrl(filename);
fdWrapper.setDownloadUrl(downloadUrl);
fdWrapper.setUploaded(true);
} else {
String error = (String) responseMap.get("error");
throw new RuntimeException("Error Upload File: " + error);
}
}
} finally {
httpclient.close();
}
fdWrapper.setChecksum(md5Checksum);
return fdWrapper;
} catch (Exception ex) {
throw ex;
}
}
public FileDownloadWrapper uploadFile(FileDescriptor fd) throws Exception {
return uploadFile(fd, false);
}
public String getFiledownloadUrl(String filename) throws Exception {
try {
int connectTimeout = 10;
int timeout = 30;
String downloadUrl = "null";
String url = "http://filedownload.unifiedtms.id:7177/apiEDC";
RequestConfig config = RequestConfig.custom().setConnectTimeout(connectTimeout * 1000).setConnectionRequestTimeout(connectTimeout * 1000).setSocketTimeout(timeout * 1000).build();
CloseableHttpClient httpclient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
HttpPost httpPost = new HttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody("fileName", filename);
builder.addTextBody("command", "get-file-from-minio");
HttpEntity reqEntity = builder.build();
httpPost.setEntity(reqEntity);
logger.info(">>> Get file: {}", filename);
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != 200) {
throw new RuntimeException("HTTP Status Not 200 (OK) : " + statusLine.getStatusCode() + " - " + statusLine.getReasonPhrase());
} else {
HttpEntity entity = response.getEntity();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
entity.writeTo(baos);
String jsonResponse = new String(baos.toByteArray());
logger.info("<<< {}", jsonResponse);
Gson gson = new Gson();
Map responseMap = gson.fromJson(jsonResponse, Map.class);
Double status = (Double) responseMap.get("status");
if (status == 200) {
// get file
downloadUrl = (String) responseMap.get("url");
} else {
String message = (String) responseMap.get("message");
throw new RuntimeException("Error Get File: " + message);
}
}
} finally {
httpclient.close();
}
return downloadUrl;
} catch (Exception ex) {
throw ex;
}
}
private String md5Checksum(InputStream is) throws Exception {
try {
String checksum = DigestUtils.md5Hex(is);
return checksum;
} finally {
if(is != null) {
is.close();
}
}
}
}

View File

@ -0,0 +1,18 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.entity.restmodel.HeartBeatRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service(HeartBeatService.NAME)
public class HeartBeatServiceBean implements HeartBeatService {
private Logger logger = LoggerFactory.getLogger(HeartBeatServiceBean.class);
@Override
public boolean heartBeat(HeartBeatRequest heartBeatRequest) {
logger.info("#heartBeat: " + heartBeatRequest);
return false;
}
}

View File

@ -0,0 +1,182 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.Singleton;
import com.cmobile.unifiedtms.config.LicenseConfig;
import com.cmobile.unifiedtms.entity.LicenseModel;
import com.haulmont.cuba.core.app.FileStorageAPI;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.AppBeans;
import com.license4j.License;
import com.license4j.LicenseText;
import com.license4j.LicenseValidator;
import com.license4j.ValidationStatus;
import com.license4j.util.FileUtils;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service(LicenseService.NAME)
public class LicenseServiceBean implements LicenseService {
private final static String LICENSE = "_LICENSE_";
private final static String productEdition = "Production";
private final static String productVersion = "1.0";
private final static String productID = "utms";
private final static String publicKey = "30820122300d06092a864886f70d01010105000382010f00303032301006072a8648ce3d02002EC311215SHA512withECDSA106052b81040006031e0004125ca10acdc54807553b11bb9b4f59fe947f68788fe9e6f0d324a03bG82010a0282010100859c388d100cacf014e7f61be9d30f5c262feadf8440affe93a85021e212a808ff6aa40e2d318ef6b298f61a68fc8bde2237fbd9241988fb7a6fe07138bab8ace340e907213daaeb7121747c5f022bd7ee5f49d49dba64883fa0674403RSA4204813SHA512withRSA7672242c571f7edb5966469150d9240464c64087727561c8cc40609b8ff0ea7e07bd08d643f6c04ef3c860092354be465bb3136cb517b0cbb5f5718f8fd95e95a33b848f01cec185afbb43062af5c8ff7f2030783371b6dbbd4f7230b1725b4dc846d1a40d7b38d369ee6df56d8a8648858b5f5b6aac61c12698dfac749bd112443bec8b9bc13e9c405053200789664afee8ed6b7dd52b264f1f58e6843bd18ae5eab76b0203010001";
@Inject
private LicenseConfig licenseConfig;
@Inject
private Logger logger;
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
private String lastLoadedLicenseString = null;
private String lastLoadedLicenseDate = null;
@Override
public LicenseModel validateLicense() throws Exception {
try {
String licenseString = licenseConfig.getLicenseString();
if(licenseString == null) {
throw new Exception("No License Provided!!");
}
String today = dateFormat.format(new Date());
if(!licenseString.equals(lastLoadedLicenseString) || !lastLoadedLicenseDate.equals(today)) {
lastLoadedLicenseString = licenseString;
lastLoadedLicenseDate = dateFormat.format(new Date());
// reloaded
} else {
// use already loaded license
return (LicenseModel) Singleton.getInstance(LICENSE).getObject();
}
logger.info("License String: {}", licenseString);
License validLicense = LicenseValidator.validate(
licenseString,
publicKey,
productID,
productEdition,
productVersion,
null,
null);
// wrap into LicenseModel
LicenseModel licenseModel = new LicenseModel();
LicenseText lt = validLicense.getLicenseText();
if(lt != null) {
licenseModel.setLicenseID(lt.getLicenseID());
licenseModel.setLicenseExpireDate(lt.getLicenseExpireDate());
licenseModel.setLicenseHardwareID(lt.getLicenseHardwareID());
licenseModel.setLicenseProductName(lt.getLicenseProductName());
licenseModel.setLicenseSignature(lt.getLicenseSignature());
licenseModel.setLicenseProperties(lt.getLicenseProperties());
licenseModel.setLicenseValidProductEdition(lt.getLicenseValidProductEdition());
licenseModel.setLicenseValidProductID(lt.getLicenseValidProductID());
licenseModel.setLicenseValidProductVersion(lt.getLicenseValidProductVersion());
licenseModel.setUserCity(lt.getUserCity());
licenseModel.setUserCompany(lt.getUserCompany());
licenseModel.setUserCity(lt.getUserCity());
licenseModel.setUserCountry(lt.getUserCountry());
licenseModel.setUserFax(lt.getUserFax());
licenseModel.setUserEmail(lt.getUserEMail());
licenseModel.setUserTelephone(lt.getUserTelephone());
licenseModel.setUserFullname(lt.getUserFullName());
licenseModel.setUserRegisteredTo(lt.getUserRegisteredTo());
licenseModel.setUserStreet(lt.getUserStreet());
licenseModel.setUserZipCode(lt.getUserZipCode());
licenseModel.setLicenseGeneratedDateTime(new Date(lt.getLicenseGenerationDateTime()));
}
licenseModel.setValidationStatus(validLicense.getValidationStatus());
// create singleton holding the loaded license
Singleton.getInstance(LICENSE).setObject(licenseModel);
return licenseModel;
} finally {}
}
@Override
public LicenseModel validateLicense(String licenseString) throws Exception {
try {
License validLicense = LicenseValidator.validate(
licenseString,
publicKey,
productID,
productEdition,
productVersion,
null,
null);
// wrap into LicenseModel
LicenseModel licenseModel = new LicenseModel();
LicenseText lt = validLicense.getLicenseText();
if(lt != null) {
licenseModel.setLicenseID(lt.getLicenseID());
licenseModel.setLicenseExpireDate(lt.getLicenseExpireDate());
licenseModel.setLicenseHardwareID(lt.getLicenseHardwareID());
licenseModel.setLicenseProductName(lt.getLicenseProductName());
licenseModel.setLicenseSignature(lt.getLicenseSignature());
licenseModel.setLicenseProperties(lt.getLicenseProperties());
licenseModel.setLicenseValidProductEdition(lt.getLicenseValidProductEdition());
licenseModel.setLicenseValidProductID(lt.getLicenseValidProductID());
licenseModel.setLicenseValidProductVersion(lt.getLicenseValidProductVersion());
licenseModel.setUserCity(lt.getUserCity());
licenseModel.setUserCompany(lt.getUserCompany());
licenseModel.setUserCity(lt.getUserCity());
licenseModel.setUserCountry(lt.getUserCountry());
licenseModel.setUserFax(lt.getUserFax());
licenseModel.setUserEmail(lt.getUserEMail());
licenseModel.setUserTelephone(lt.getUserTelephone());
licenseModel.setUserFullname(lt.getUserFullName());
licenseModel.setUserRegisteredTo(lt.getUserRegisteredTo());
licenseModel.setUserStreet(lt.getUserStreet());
licenseModel.setUserZipCode(lt.getUserZipCode());
licenseModel.setLicenseGeneratedDateTime(new Date(lt.getLicenseGenerationDateTime()));
}
licenseModel.setValidationStatus(validLicense.getValidationStatus());
return licenseModel;
} finally {}
}
@Override
public ValidationStatus installLicense(String licenseString) throws Exception {
try {
License validLicense = LicenseValidator.validate(
licenseString,
publicKey,
productID,
productEdition,
productVersion,
null,
null);
if(ValidationStatus.LICENSE_VALID == validLicense.getValidationStatus()) {
licenseConfig.setLicenseString(licenseString);
} else {
// invalid license
}
return validLicense.getValidationStatus();
} finally {}
}
@Override
public String getLicenseStringFromFile(FileDescriptor fileDescriptor) throws Exception {
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
byte[] licenseBytes = fileStorageAPI.loadFile(fileDescriptor);
String licenseString = readFile(licenseBytes);
return licenseString;
}
private String readFile(byte[] bytes) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)));
StringBuilder stringBuilder = new StringBuilder();
String str;
while ((str = bufferedReader.readLine()) != null) {
stringBuilder.append(str);
stringBuilder.append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,296 @@
package com.cmobile.unifiedtms.service;
import com.haulmont.addon.sdbmt.core.app.multitenancy.TenantProvider;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashSet;
import java.util.Set;
@Service(NumericInfoWidgetService.NAME)
public class NumericInfoWidgetServiceBean implements NumericInfoWidgetService {
private Logger logger = LoggerFactory.getLogger(NumericInfoWidgetServiceBean.class);
@Inject
private Persistence persistence;
@Inject
private TenantProvider tenantProvider;
@Override
public Number getNumberFromQueryTemplate(String queryTemplate) {
if("active-terminal".equals(queryTemplate)) {
return getActiveTerminal();
} else if("total-terminal".equals(queryTemplate)) {
return getTotalTerminal();
} else if("total-apps".equals(queryTemplate)) {
return getTotalApps();
} else if("download-task".equals(queryTemplate)) {
return getTotalInProgressDownloadTask();
} else if("total-download".equals(queryTemplate)) {
return getTotalDownload();
} else if("today-download".equals(queryTemplate)) {
return getTotalTodayDownload();
} else if("terminal-offline-1-hour".equals(queryTemplate)) {
return getOfflineTerminal1Hour();
} else if("terminal-offline-6-hours".equals(queryTemplate)) {
return getOfflineTerminal6Hours();
} else if("terminal-offline-12-hours".equals(queryTemplate)) {
return getOfflineTerminal12Hours();
} else if("terminal-offline-1-day".equals(queryTemplate)) {
return getOfflineTerminal1Day();
} else if("terminal-offline-1-week".equals(queryTemplate)) {
return getOfflineTerminal1Week();
} else if("terminal-offline-1-month".equals(queryTemplate)) {
return getOfflineTerminal1Month();
}
return null;
}
private Double _getValueFromQuery(String query) {
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
Set<Double> numbers = runner.query(query,
new ResultSetHandler<Set<Double>>() {
@Nullable
@Override
public Set<Double> handle(ResultSet rs) throws SQLException {
Set<Double> rows = new HashSet<Double>();
while (rs.next()) {
rows.add(rs.getDouble(1));
}
return rows;
}
});
return numbers.isEmpty() ? null : numbers.toArray(new Double[] {})[0];
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
private Double _getValueFromQuery(String query, String tenantId) {
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
Set<Double> numbers = runner.query(query,
new String[] { tenantId },
new int[] { Types.VARCHAR },
new ResultSetHandler<Set<Double>>() {
@Nullable
@Override
public Set<Double> handle(ResultSet rs) throws SQLException {
Set<Double> rows = new HashSet<Double>();
while (rs.next()) {
rows.add(rs.getDouble(1));
}
return rows;
}
});
return numbers.isEmpty() ? null : numbers.toArray(new Double[] {})[0];
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* TODO: filter only active terminal
*/
private Integer getActiveTerminal() {
String tenantId = tenantProvider.getCurrentUserTenantId();
logger.info("#getActiveTerminal: '" + tenantId + "'");
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery("select count(*) _value from ( select id from tms_terminal t where t.heartbeat_status=1 and t.delete_ts is null ) s");
} else {
value = _getValueFromQuery("select count(*) _value from ( select id from tms_terminal t where t.tenant_id=? and t.heartbeat_status=1 and t.delete_ts is null ) s", tenantId);
}
logger.info("--> value: '" + value + "'");
return value != null ? value.intValue() : null;
}
private Integer getTotalTerminal() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery("select count(*) _value from ( select id from tms_terminal where delete_ts is null ) t");
} else {
value = _getValueFromQuery("select count(*) _value from ( select id from tms_terminal where tenant_id=? and delete_ts is null ) t", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getTotalApps() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery("select count(*) _value from tms_application where delete_ts is null");
} else {
value = _getValueFromQuery("select count(*) _value from tms_application where tenant_id=? and delete_ts is null", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getTotalInProgressDownloadTask() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery("select count(*) _value from tms_download_task where status = 2 and delete_ts is null");
} else {
value = _getValueFromQuery("select count(*) _value from tms_download_task where tenant_id=? and status = 2 and delete_ts is null", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getTotalDownload() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(distinct log.id) _value "
+ "from tms_download_task task "
+ " inner join tms_download_task_application_link link on link.download_task_id=task.id "
+ " inner join tms_download_task_log log on log.task_id=task.id and log.application_id=link.application_id "
+ "where task.delete_ts is null and log.activity <> 1");
} else {
value = _getValueFromQuery(""
+ "select count(distinct log.id) _value "
+ "from tms_download_task task "
+ " inner join tms_download_task_application_link link on link.download_task_id=task.id "
+ " inner join tms_download_task_log log on log.task_id=task.id and log.application_id=link.application_id "
+ "where task.tenant_id = ? and task.delete_ts is null and log.activity <> 1", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getTotalTodayDownload() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(distinct log.id) _value "
+ "from tms_download_task task "
+ " inner join tms_download_task_application_link link on link.download_task_id=task.id "
+ " inner join tms_download_task_log log on log.task_id=task.id and log.application_id=link.application_id "
+ " and (task.create_ts::date = CURRENT_DATE or task.update_ts::date = CURRENT_DATE) "
+ "where task.delete_ts is null and log.activity in (2,3,4,5,6,7)");
} else {
value = _getValueFromQuery(""
+ "select count(distinct log.id) _value "
+ "from tms_download_task task "
+ " inner join tms_download_task_application_link link on link.download_task_id=task.id "
+ " inner join tms_download_task_log log on log.task_id=task.id and log.application_id=link.application_id "
+ " and (task.create_ts::date = CURRENT_DATE or task.update_ts::date = CURRENT_DATE) "
+ "where task.tenant_id = ? and task.delete_ts is null and log.activity in (2,3,4,5,6,7)", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getOfflineTerminal1Hour() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 hour')");
} else {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 hour') and task.tenant_id", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getOfflineTerminal6Hours() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '6 hours')");
} else {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '6 hours') and task.tenant_id", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getOfflineTerminal12Hours() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '12 hours')");
} else {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '12 hours') and task.tenant_id", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getOfflineTerminal1Day() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 day')");
} else {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 day') and task.tenant_id", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getOfflineTerminal1Week() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 week')");
} else {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 week') and task.tenant_id", tenantId);
}
return value != null ? value.intValue() : null;
}
private Integer getOfflineTerminal1Month() {
String tenantId = tenantProvider.getCurrentUserTenantId();
Double value =null;
if(tenantId == null || "no_tenant".equals(tenantId)) {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 month')");
} else {
value = _getValueFromQuery(""
+ "select count(*) total "
+ "from tms_terminal "
+ "where delete_ts is null and last_heartbeat_time < (now() - interval '1 month') and task.tenant_id", tenantId);
}
return value != null ? value.intValue() : null;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.entity.ResponseCode;
import com.cmobile.unifiedtms.entity.enums.TrxType;
import com.cmobile.unifiedtms.ext.utils.XlsHelper;
import org.springframework.stereotype.Service;
import com.cmobile.unifiedtms.ext.entity.Card;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.app.FileStorageAPI;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.*;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import com.cmobile.unifiedtms.ext.exception.ImportFileEofEvaluationException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service(ResponseCodeService.NAME)
public class ResponseCodeServiceBean implements ResponseCodeService {
protected static final char NON_BREAKING_SPACE = (char) 160;
private Sheet sheet = null;
private int sheetIndex = 0;
protected FileDescriptor fileDescriptor;
protected Persistence persistence;
protected Metadata metadata;
protected TimeSource timeSource;
protected int firstDataRowIndex = 0;
protected int dataRowIncrement = 1;
protected Map<String, Integer> attributesToColumns;
protected int currentRowIndex;
public static final String TRX_TYPE = "type";
public static final String CODE = "code";
public static final String DESCRIPTION = "description";
@Override
public List<ResponseCode> parseResponseCodeFromFile(FileDescriptor fd) throws Exception {
List<ResponseCode> list = new ArrayList<ResponseCode>();
{
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
byte[] xlsFile = fileStorageAPI.loadFile(fd);
Workbook workbook = XlsHelper.openWorkbook(xlsFile);
if (workbook == null) {
throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, "File was not loaded");
}
sheet = workbook.getSheetAt(sheetIndex);
persistence = AppBeans.get(Persistence.NAME);
metadata = AppBeans.get(Metadata.NAME);
timeSource = AppBeans.get(TimeSource.NAME);
attributesToColumns = createAttributesToColumns();
// read the values
firstDataRowIndex = 1;
try {
for (currentRowIndex = firstDataRowIndex; !eof(sheet.getRow(currentRowIndex)); currentRowIndex += dataRowIncrement) {
Row row = sheet.getRow(currentRowIndex);
ResponseCode responseCode = metadata.create(ResponseCode.class);
String trxType = (String) XlsHelper.getCellValue(row.getCell(attributesToColumns.get(TRX_TYPE)));
String code = String.valueOf(XlsHelper.getCellValue(row.getCell(attributesToColumns.get(CODE))));
String description = String.valueOf(XlsHelper.getCellValue(row.getCell(attributesToColumns.get(DESCRIPTION))));
responseCode.setType(TrxType.fromId(trxType));
responseCode.setCode(code);
responseCode.setDesc(description);
list.add(responseCode);
}
} catch (ImportFileEofEvaluationException e) {
throw new RuntimeException(e);
}
}
return list;
}
private Boolean eofByColumnNullValue(Row row, String columnAlias) throws ImportFileEofEvaluationException {
Integer columnNumber = attributesToColumns.get(columnAlias);
if (row != null) {
Cell cell = row.getCell(columnNumber);
Object cellValue;
try {
cellValue = XlsHelper.getCellValue(cell);
} catch (Exception e) {
throw new ImportFileEofEvaluationException(String.format("Eof evaluation has failed on row %s", row.getRowNum()));
}
return cellValue == null;
}
return true;
}
private Map<String, Integer> createAttributesToColumns() {
Map<String, Integer> columns = new HashMap<>();
columns.put(TRX_TYPE, 0);
columns.put(CODE, 1);
columns.put(DESCRIPTION, 2);
return columns;
}
protected boolean eof(Row row) throws ImportFileEofEvaluationException {
return eofByColumnNullValue(row, TRX_TYPE);
}
}

View File

@ -0,0 +1,102 @@
package com.cmobile.unifiedtms.service;
import com.haulmont.addon.sdbmt.core.app.multitenancy.TenantProvider;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
@Service(TerminalExtService.NAME)
public class TerminalExtServiceBean implements TerminalExtService {
private Logger logger = LoggerFactory.getLogger(TerminalExtServiceBean.class);
@Inject
private Persistence persistence;
@Inject
private TenantProvider tenantProvider;
public String updateTerminalStatus() {
String query = "select datas.arr[0] status,datas.arr[1] message from ("
+ "select update_terminal_status() arr "
+ ") datas";
String[] params = new String[] {
};
logger.info("update_terminal_status()");
int[] types = new int[] {
};
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
String[] datas = runner.query(query,
params,
types,
new ResultSetHandler<String[]>() {
@Nullable
@Override
public String[] handle(ResultSet rs) throws SQLException {
if(rs.next()) {
String[] ret = new String[2];
ret[0] = rs.getString(1);
ret[1] = rs.getString(2);
return ret;
}
return null;
}
});
StringBuilder sb = new StringBuilder();
if(datas != null) {
sb.append("[").append(datas[0]).append(", ").append(datas[1]).append("]");
}
return sb.toString();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public String removeTerminalByTid(String terminalId) {
String query = "select datas.arr[0] status,datas.arr[1] message from ("
+ "select remove_terminal_by_tid(?) arr "
+ ") datas";
String[] params = new String[] {
terminalId
};
logger.info("remove_terminal_by_tid()");
int[] types = new int[] {
Types.VARCHAR,
};
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
String[] datas = runner.query(query,
params,
types,
new ResultSetHandler<String[]>() {
@Nullable
@Override
public String[] handle(ResultSet rs) throws SQLException {
if(rs.next()) {
String[] ret = new String[2];
ret[0] = rs.getString(1);
ret[1] = rs.getString(2);
return ret;
}
return null;
}
});
StringBuilder sb = new StringBuilder();
if(datas != null) {
sb.append("[").append(datas[0]).append(", ").append(datas[1]).append("]");
}
return sb.toString();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,461 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.misc.TerminalGroupImportObjectWrapper;
import com.cmobile.unifiedtms.exception.ImportFileEofEvaluationException;
import com.cmobile.unifiedtms.ext.entity.TerminalExt;
import com.cmobile.unifiedtms.utils.XlsHelper;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.app.FileStorageAPI;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.sql.*;
import java.util.*;
@Service(TerminalGroupImporterService.NAME)
public class TerminalGroupImporterServiceBean implements TerminalGroupImporterService {
@Inject
private Logger logger;
@Inject
private DataManager dataManager;
@Inject
private Persistence persistence;
private Log log = LogFactory.getLog(this.getClass());
protected static final char NON_BREAKING_SPACE = (char) 160;
protected FileDescriptor fileDescriptor;
protected Metadata metadata;
protected int firstDataRowIndex = 0;
protected int dataRowIncrement = 1;
protected Map<String, Integer> terminalAttributesToColumns;
protected int currentRowIndex;
public static final String TID = "TID";
public static final String SN = "SN";
private static final int TERMINAL_LOOKUP_BATCH_SIZE = 500;
private static final int TERMINAL_ATTACH_BATCH_SIZE = 1000;
@Override
public List<TerminalGroupImportObjectWrapper> parseTerminalsFromFile(FileDescriptor fd) throws Exception {
List<TerminalGroupImportObjectWrapper> terminals = new ArrayList<>();
Workbook workbook = null;
{
long startTime = System.currentTimeMillis();
logger.info("Terminal group import started. fileDescriptorId={}, fileName={}", fd.getId(), fd.getName());
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
long loadFileStartTime = System.currentTimeMillis();
byte[] xlsFile = fileStorageAPI.loadFile(fd);
logger.info("Terminal group import file loaded. size={} bytes, elapsed={} ms",
xlsFile != null ? xlsFile.length : 0, System.currentTimeMillis() - loadFileStartTime);
long openWorkbookStartTime = System.currentTimeMillis();
workbook = XlsHelper.openWorkbook(xlsFile);
logger.info("Terminal group import workbook opened in {} ms",
System.currentTimeMillis() - openWorkbookStartTime);
if (workbook == null) {
throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, "File was not loaded");
}
Sheet terminalSheet = workbook.getSheetAt(0);
logger.info("Terminal group import sheet selected. sheetName={}, lastRowNum={}",
terminalSheet.getSheetName(), terminalSheet.getLastRowNum());
_parseTerminalsFromFile(workbook, terminalSheet, terminals);
logger.info("Terminal group import finished. total={}, elapsed={} ms",
terminals.size(), System.currentTimeMillis() - startTime);
}
return terminals;
}
@Override
public List<TerminalGroupImportObjectWrapper> parseTerminalsFromFileOptimized(FileDescriptor fd) throws Exception {
List<TerminalGroupImportObjectWrapper> terminals = new ArrayList<>();
long startTime = System.currentTimeMillis();
logger.info("Optimized terminal group import started. fileDescriptorId={}, fileName={}", fd.getId(), fd.getName());
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
byte[] xlsFile = fileStorageAPI.loadFile(fd);
Workbook workbook = XlsHelper.openWorkbook(xlsFile);
if (workbook == null) {
throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, "File was not loaded");
}
Sheet terminalSheet = workbook.getSheetAt(0);
List<TerminalGroupImportObjectWrapper> parsedTerminals = parseTerminalRows(terminalSheet);
logger.info("Optimized terminal group import parsed {} rows. Matching terminals using import staging table ...",
parsedTerminals.size());
matchTerminalsUsingImportStage(parsedTerminals);
terminals.addAll(parsedTerminals);
logger.info("Optimized terminal group import finished. total={}, elapsed={} ms",
terminals.size(), System.currentTimeMillis() - startTime);
return terminals;
}
private void _parseTerminalsFromFile(Workbook workbook, Sheet sheet, List<TerminalGroupImportObjectWrapper> terminals) throws Exception {
{
metadata = AppBeans.get(Metadata.NAME);
terminalAttributesToColumns = createTerminalAttributesToColumns();
// read the values
firstDataRowIndex = 1;
try {
List<TerminalGroupImportObjectWrapper> parsedTerminals = new ArrayList<>();
Set<String> serialNumbers = new LinkedHashSet<>();
for (currentRowIndex = firstDataRowIndex; !eofTerminal(sheet.getRow(currentRowIndex)); currentRowIndex += dataRowIncrement) {
Row row = sheet.getRow(currentRowIndex);
if (currentRowIndex > firstDataRowIndex && currentRowIndex % 1000 == 0) {
logger.info("Terminal group import reading row {}", currentRowIndex);
}
String tid = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TID)));
String sn = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(SN)));
if(sn != null) {
sn = sn.trim().toUpperCase();
if (!sn.isEmpty()) {
serialNumbers.add(sn);
}
}
TerminalGroupImportObjectWrapper terminalGroupImportObjectWrapper = new TerminalGroupImportObjectWrapper();
terminalGroupImportObjectWrapper.setTid(tid);
terminalGroupImportObjectWrapper.setSn(sn);
parsedTerminals.add(terminalGroupImportObjectWrapper);
}
logger.info("Terminal group import parsed {} rows with {} unique SNs. Loading terminals ...",
parsedTerminals.size(), serialNumbers.size());
long loadTerminalsStartTime = System.currentTimeMillis();
Map<String, Terminal> terminalsBySn = loadTerminalsBySN(serialNumbers);
logger.info("Terminal group import loaded {} matching terminals in {} ms",
terminalsBySn.size(), System.currentTimeMillis() - loadTerminalsStartTime);
for (TerminalGroupImportObjectWrapper terminalGroupImportObjectWrapper : parsedTerminals) {
Terminal terminal = terminalGroupImportObjectWrapper.getSn() != null
? terminalsBySn.get(terminalGroupImportObjectWrapper.getSn().toLowerCase())
: null;
terminalGroupImportObjectWrapper.setTerminal(terminal);
if (terminal != null) {
terminalGroupImportObjectWrapper.setSnFound(true);
if(terminal.getTerminalLink() != null) {
TerminalExt terminalExt = terminal.getTerminalLink().getTerminalExt();
String terminalId = terminalExt != null ? terminalExt.getTerminalId() : null;
String importedTid = terminalGroupImportObjectWrapper.getTid();
terminalGroupImportObjectWrapper.setTidFound(terminalId != null
&& importedTid != null
&& terminalId.equalsIgnoreCase(importedTid));
} else {
terminalGroupImportObjectWrapper.setTidFound(false);
}
} else {
terminalGroupImportObjectWrapper.setSnFound(false);
terminalGroupImportObjectWrapper.setTidFound(false);
}
// add to terminals
terminals.add(terminalGroupImportObjectWrapper);
}
} catch (ImportFileEofEvaluationException e) {
throw new RuntimeException(e);
}
}
}
private Map<String, Terminal> loadTerminalsBySN(Set<String> serialNumbers) {
Map<String, Terminal> terminalsBySn = new HashMap<>();
if (serialNumbers.isEmpty()) {
return terminalsBySn;
}
List<String> serialNumberList = new ArrayList<>(serialNumbers);
for (int start = 0; start < serialNumberList.size(); start += TERMINAL_LOOKUP_BATCH_SIZE) {
int end = Math.min(start + TERMINAL_LOOKUP_BATCH_SIZE, serialNumberList.size());
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where t.sn in :sns and t.deleteTs is null");
loadContext.getQuery().setParameter("sns", serialNumberList.subList(start, end));
loadContext.setView("terminal-linked-view");
List<Terminal> batch = dataManager.loadList(loadContext);
for (Terminal terminal : batch) {
if (terminal.getSn() != null) {
terminalsBySn.put(terminal.getSn().toLowerCase(), terminal);
}
}
}
return terminalsBySn;
}
private List<TerminalGroupImportObjectWrapper> parseTerminalRows(Sheet sheet) throws Exception {
metadata = AppBeans.get(Metadata.NAME);
terminalAttributesToColumns = createTerminalAttributesToColumns();
firstDataRowIndex = 1;
List<TerminalGroupImportObjectWrapper> parsedTerminals = new ArrayList<>();
for (currentRowIndex = firstDataRowIndex; !eofTerminal(sheet.getRow(currentRowIndex)); currentRowIndex += dataRowIncrement) {
Row row = sheet.getRow(currentRowIndex);
if (currentRowIndex > firstDataRowIndex && currentRowIndex % 1000 == 0) {
logger.info("Terminal group import reading row {}", currentRowIndex);
}
String tid = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TID)));
String sn = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(SN)));
if (sn != null) {
sn = sn.trim().toUpperCase();
}
TerminalGroupImportObjectWrapper terminalGroupImportObjectWrapper = new TerminalGroupImportObjectWrapper();
terminalGroupImportObjectWrapper.setTid(tid);
terminalGroupImportObjectWrapper.setSn(sn);
parsedTerminals.add(terminalGroupImportObjectWrapper);
}
return parsedTerminals;
}
private void matchTerminalsUsingImportStage(List<TerminalGroupImportObjectWrapper> parsedTerminals) {
if (parsedTerminals.isEmpty()) {
return;
}
UUID importId = UUID.randomUUID();
logger.info("Terminal group optimized import matching started. importId={}, rows={}", importId, parsedTerminals.size());
Map<Integer, TerminalGroupImportObjectWrapper> wrappersByRowNo = new HashMap<>();
Map<UUID, List<TerminalGroupImportObjectWrapper>> wrappersByTerminalId = new LinkedHashMap<>();
Connection connection = null;
boolean originalAutoCommit = true;
try {
connection = persistence.getDataSource().getConnection();
originalAutoCommit = connection.getAutoCommit();
connection.setAutoCommit(false);
long cleanupStartTime = System.currentTimeMillis();
cleanupStaleImportStageRows(connection);
logger.info("Terminal group optimized import stale stage cleanup finished. importId={}, elapsed={} ms",
importId, System.currentTimeMillis() - cleanupStartTime);
long insertStartTime = System.currentTimeMillis();
insertImportStageRows(connection, importId, parsedTerminals, wrappersByRowNo);
logger.info("Terminal group optimized import stage insert finished. importId={}, rows={}, elapsed={} ms",
importId, parsedTerminals.size(), System.currentTimeMillis() - insertStartTime);
long queryStartTime = System.currentTimeMillis();
queryImportStageMatches(connection, importId, wrappersByRowNo, wrappersByTerminalId);
logger.info("Terminal group optimized import match query finished. importId={}, matchedTerminalIds={}, elapsed={} ms",
importId, wrappersByTerminalId.size(), System.currentTimeMillis() - queryStartTime);
connection.commit();
} catch (SQLException e) {
rollbackQuietly(connection);
throw new RuntimeException("Error matching terminal group import data using import staging table", e);
} finally {
cleanupImportStageRows(connection, importId);
restoreAutoCommitQuietly(connection, originalAutoCommit);
closeQuietly(connection);
}
long attachStartTime = System.currentTimeMillis();
attachMatchedTerminals(wrappersByTerminalId);
logger.info("Terminal group optimized import matching finished. importId={}, elapsed={} ms",
importId, System.currentTimeMillis() - attachStartTime);
}
private void cleanupStaleImportStageRows(Connection connection) throws SQLException {
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("delete from tms_terminal_group_import_stage " +
"where create_ts < current_timestamp - interval '1 day'");
}
}
private void insertImportStageRows(Connection connection,
UUID importId,
List<TerminalGroupImportObjectWrapper> parsedTerminals,
Map<Integer, TerminalGroupImportObjectWrapper> wrappersByRowNo) throws SQLException {
String sql = "insert into tms_terminal_group_import_stage " +
"(import_id, row_no, tid, sn, tid_norm, sn_norm, sn_lower_norm) values (?, ?, ?, ?, ?, ?, ?)";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
int rowNo = 0;
for (TerminalGroupImportObjectWrapper wrapper : parsedTerminals) {
rowNo++;
wrappersByRowNo.put(rowNo, wrapper);
statement.setObject(1, importId);
statement.setInt(2, rowNo);
statement.setString(3, wrapper.getTid());
statement.setString(4, wrapper.getSn());
statement.setString(5, normalizeImportValue(wrapper.getTid()));
statement.setString(6, normalizeImportValue(wrapper.getSn()));
statement.setString(7, normalizeImportValueLower(wrapper.getSn()));
statement.addBatch();
if (rowNo % 1000 == 0) {
statement.executeBatch();
}
}
statement.executeBatch();
}
}
private void queryImportStageMatches(Connection connection,
UUID importId,
Map<Integer, TerminalGroupImportObjectWrapper> wrappersByRowNo,
Map<UUID, List<TerminalGroupImportObjectWrapper>> wrappersByTerminalId) throws SQLException {
String sql = "select i.row_no, t.id, te.terminal_id " +
"from tms_terminal_group_import_stage i " +
"left join tms_terminal t on t.sn in (i.sn, i.sn_norm, i.sn_lower_norm) and t.delete_ts is null " +
"left join tms_terminal_link tl on tl.terminal_id = t.id " +
"left join tmsext_terminal_ext te on te.id = tl.terminal_ext_id and te.delete_ts is null " +
"where i.import_id = ? " +
"order by i.row_no";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setObject(1, importId);
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
int rowNo = resultSet.getInt(1);
UUID terminalId = (UUID) resultSet.getObject(2);
String terminalExtTid = resultSet.getString(3);
TerminalGroupImportObjectWrapper wrapper = wrappersByRowNo.get(rowNo);
if (wrapper == null) {
continue;
}
boolean snFound = terminalId != null;
wrapper.setSnFound(snFound);
wrapper.setTidFound(snFound
&& terminalExtTid != null
&& wrapper.getTid() != null
&& normalizeImportValue(terminalExtTid).equals(normalizeImportValue(wrapper.getTid())));
if (snFound) {
wrappersByTerminalId.computeIfAbsent(terminalId, id -> new ArrayList<>()).add(wrapper);
}
}
}
}
}
private void cleanupImportStageRows(Connection connection, UUID importId) {
if (connection == null || importId == null) {
return;
}
try (PreparedStatement statement = connection.prepareStatement(
"delete from tms_terminal_group_import_stage where import_id = ?")) {
if (connection.getAutoCommit()) {
statement.setObject(1, importId);
statement.executeUpdate();
} else {
statement.setObject(1, importId);
statement.executeUpdate();
connection.commit();
}
} catch (SQLException e) {
logger.warn("Unable to cleanup terminal group import staging rows. importId={}", importId, e);
}
}
private void attachMatchedTerminals(Map<UUID, List<TerminalGroupImportObjectWrapper>> wrappersByTerminalId) {
if (wrappersByTerminalId.isEmpty()) {
return;
}
List<UUID> terminalIds = new ArrayList<>(wrappersByTerminalId.keySet());
for (int start = 0; start < terminalIds.size(); start += TERMINAL_ATTACH_BATCH_SIZE) {
int end = Math.min(start + TERMINAL_ATTACH_BATCH_SIZE, terminalIds.size());
LoadContext<Terminal> loadContext = LoadContext.create(Terminal.class);
loadContext.setQueryString("select t from tms_Terminal t where t.id in :ids and t.deleteTs is null");
loadContext.getQuery().setParameter("ids", terminalIds.subList(start, end));
loadContext.setView("terminal-linked-view");
List<Terminal> terminals = dataManager.loadList(loadContext);
for (Terminal terminal : terminals) {
List<TerminalGroupImportObjectWrapper> wrappers = wrappersByTerminalId.get(terminal.getId());
if (wrappers != null) {
for (TerminalGroupImportObjectWrapper wrapper : wrappers) {
wrapper.setTerminal(terminal);
}
}
}
}
}
private String normalizeImportValue(String value) {
return value != null ? value.trim().toUpperCase() : null;
}
private String normalizeImportValueLower(String value) {
return value != null ? value.trim().toLowerCase() : null;
}
private void rollbackQuietly(Connection connection) {
if (connection != null) {
try {
connection.rollback();
} catch (SQLException ignored) {
}
}
}
private void restoreAutoCommitQuietly(Connection connection, boolean autoCommit) {
if (connection != null) {
try {
connection.setAutoCommit(autoCommit);
} catch (SQLException ignored) {
}
}
}
private void closeQuietly(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException ignored) {
}
}
}
private Boolean eofByColumnNullValueTerminal(Row row, String columnAlias) throws ImportFileEofEvaluationException {
Integer columnNumber = terminalAttributesToColumns.get(columnAlias);
if (row != null) {
Cell cell = row.getCell(columnNumber);
Object cellValue;
try {
cellValue = XlsHelper.getCellValue(cell);
} catch (Exception e) {
throw new ImportFileEofEvaluationException(String.format("Eof evaluation has failed on row %s", row.getRowNum()));
}
return cellValue == null;
}
return true;
}
private Map<String, Integer> createTerminalAttributesToColumns() {
Map<String, Integer> columns = new HashMap<>();
columns.put(TID, 0);
columns.put(SN, 1);
return columns;
}
protected boolean eofTerminal(Row row) throws ImportFileEofEvaluationException {
return eofByColumnNullValueTerminal(row, TID);
}
}

View File

@ -0,0 +1,811 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.entity.*;
import com.cmobile.unifiedtms.entity.chartdata.PieChartData;
import com.cmobile.unifiedtms.entity.misc.TerminalImporterObjectWrapper;
import com.cmobile.unifiedtms.exception.ImportFileEofEvaluationException;
import com.cmobile.unifiedtms.ext.entity.Acquirer;
import com.cmobile.unifiedtms.ext.entity.Card;
import com.cmobile.unifiedtms.ext.entity.Issuer;
import com.cmobile.unifiedtms.ext.entity.TerminalExt;
import com.cmobile.unifiedtms.entity.TerminalImportBean;
import com.cmobile.unifiedtms.utils.XlsHelper;
import com.haulmont.addon.sdbmt.core.app.multitenancy.TenantProvider;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.bali.db.ResultSetHandler;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.app.FileStorageAPI;
import com.haulmont.cuba.core.entity.FileDescriptor;
import com.haulmont.cuba.core.global.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.SpreadsheetVersion;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import javax.annotation.Nullable;
import javax.inject.Inject;
@Service(TerminalImporterService.NAME)
public class TerminalImporterServiceBean implements TerminalImporterService {
@Inject
private DataManager dataManager;
@Inject
private MetadataTools metadataTools;
@Inject
private UuidSource uuidSource;
@Inject
private Persistence persistence;
@Inject
private UserSessionSource userSessionSource;
@Inject
private TenantProvider tenantProvider;
@Inject
private Logger logger;
private Log log = LogFactory.getLog(this.getClass());
protected static final char NON_BREAKING_SPACE = (char) 160;
protected FileDescriptor fileDescriptor;
protected Metadata metadata;
protected int firstDataRowIndex = 0;
protected int dataRowIncrement = 1;
protected Map<String, Integer> terminalAttributesToColumns;
protected Map<String, Integer> terminalEditAttributesToColumns;
protected int currentRowIndex;
public static final String SN = "SN";
public static final String IMEI = "IMEI";
public static final String MODEL_NAME = "ModelName";
public static final String MERCHANT_NAME = "MerchantName";
public static final String PROFILE_NAME = "ProfileName";
public static final String GROUP_NAMES = "GroupNames";
public static final String TEMPLATE_TERMINAL_ID = "TemplateTerminalID";
public static final String TERMINAL_ID = "TerminalID";
public static final String MERCHANT_ID = "MerchantID";
public static final String MERCHANT_NAME1 = "MerchantName1";
public static final String MERCHANT_NAME2 = "MerchantName2";
public static final String MERCHANT_NAME3 = "MerchantName3";
public static final String MERCHANT_NAME4 = "MerchantName4";
public static final String MERCHANT_NAME5 = "MerchantName5";
// local caches
private Map<UUID, List<Card>> issuerCards = new HashMap<>();
private Map<UUID, UUID> issuerIds = new HashMap<>();
private Map<String, TerminalExt> terminalTemplateCaches = new HashMap<>();
@Override
public TerminalImporterObjectWrapper parseTerminalsFromFile(FileDescriptor fd) throws Exception {
List<TerminalLink> terminalLinks = new ArrayList<>();
{
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
byte[] xlsFile = fileStorageAPI.loadFile(fd);
Workbook workbook = XlsHelper.openWorkbook(xlsFile);
if (workbook == null) {
throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, "File was not loaded");
}
Sheet terminalSheet = workbook.getSheetAt(0);
issuerIds.clear();
issuerCards.clear();
terminalTemplateCaches.clear();
_parseTerminalsFromFile(workbook, terminalSheet, terminalLinks);
// save the data
//saveTerminals(terminalLinks);
}
return new TerminalImporterObjectWrapper(terminalLinks);
}
@Override
public List<TerminalExt> parseTerminalsFromEditFile(FileDescriptor fd) throws Exception {
List<TerminalExt> terminals = new ArrayList<>();
{
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
byte[] xlsFile = fileStorageAPI.loadFile(fd);
Workbook workbook = XlsHelper.openWorkbook(xlsFile);
if (workbook == null) {
throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, "File was not loaded");
}
Sheet terminalSheet = workbook.getSheetAt(0);
_parseTerminalsFromEditFile(workbook, terminalSheet, terminals);
}
return terminals;
}
@Override
public boolean saveTerminal(TerminalLink terminalLink) throws Exception {
log.info("Saving terminal link ...");
/*
Transaction tx = persistence.createTransaction();
try {
// prepare commit context
CommitContext commitContext = new CommitContext();
// Terminal
Terminal terminal = terminalLink.getTerminal();
// Terminal Ext
TerminalExt terminalExt = terminalLink.getTerminalExt();
// Order of saving
// 1. Terminal
// 2. Terminal Ext
// 3. Acquirers
// 4. Issuers + Link Card
commitContext.addInstanceToCommit(terminal);
commitContext.addInstanceToCommit(terminalExt);
terminalExt.getAcquirers().forEach(acquirer -> {
log.info(">>>> Acquirer#id: " + acquirer.getId() + " (" + acquirer.getName() + ")");
acquirer.setTerminalExt(terminalExt);
commitContext.addInstanceToCommit(acquirer);
acquirer.getIssuers().forEach(issuer -> {
issuer.setAcquirer(acquirer);
log.info(">>>> Issuer#id: " + issuer.getId() + " (" + issuer.getName() + ")");
commitContext.addInstanceToCommit(issuer);
});
});
commitContext.addInstanceToCommit(terminalLink);
dataManager.commit(commitContext);
commitContext.getCommitInstances().clear();
// last one save cards
LoadContext<Issuer> issLoadContext = LoadContext.create(Issuer.class);
terminalExt.getAcquirers().forEach(acquirer -> {
acquirer.getIssuers().forEach(_issuer -> {
issLoadContext.setId(_issuer.getId());
issLoadContext.setView("issuer-view");
Issuer issuer = dataManager.load(issLoadContext);
UUID oldIssuerId = issuerIds.get(_issuer.getId());
List<Card> oldCards = issuerCards.get(oldIssuerId);
List<Card> cards = new ArrayList<>();
for(Card _card : oldCards) {
cards.add(_card);
}
issuer.setCards(cards);
System.out.println("TOTAL CARDS: " + issuer.getCards().size());
dataManager.commit(issuer);
});
});
tx.commit();
return true;
} catch(Exception ex) {
throw ex;
} finally {
log.info("Saving terminal link DONE");
}*/
return false;
}
@Override
public List<TerminalImportBean> parseTerminalsFromFile2(FileDescriptor fd) throws Exception {
List<TerminalImportBean> terminals = new ArrayList<>();
{
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
byte[] xlsFile = fileStorageAPI.loadFile(fd);
Workbook workbook = XlsHelper.openWorkbook(xlsFile);
if (workbook == null) {
throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, "File was not loaded");
}
Sheet terminalSheet = workbook.getSheetAt(0);
_parseTerminalsFromFile2(workbook, terminalSheet, terminals);
}
return terminals;
}
@Override
public List<TerminalProfilingItem> parseProfilingItems(FileDescriptor fd) throws Exception {
List<TerminalProfilingItem> items = new ArrayList<>();
{
FileStorageAPI fileStorageAPI = AppBeans.get(FileStorageAPI.NAME);
byte[] xlsFile = fileStorageAPI.loadFile(fd);
Workbook workbook = XlsHelper.openWorkbook(xlsFile);
if (workbook == null) {
throw new FileStorageException(FileStorageException.Type.FILE_NOT_FOUND, "File was not loaded");
}
Sheet terminalSheet = workbook.getSheetAt(0);
_parseProfilingItemsFromFile(workbook, terminalSheet, items);
}
return items;
}
@Override
public String[] saveTerminal(TerminalImportBean terminal) throws Exception {
String tenantId = tenantProvider.getCurrentUserTenantId();
if("no_tenant".equals(tenantId)) {
tenantId = null;
}
String query = "select datas.arr[0] status,datas.arr[1] message from ("
+ "select profiling_terminal(?,?,?,?,?,?,?,?,?,?,?,?,?,?) arr "
+ ") datas";
String[] params = new String[] {
terminal.getSn(),
terminal.getImei(),
terminal.getModelName(),
terminal.getMerchantName(),
terminal.getProfileName(),
terminal.getGroupNames(),
terminal.getTemplateTerminalId(),
terminal.getTerminalId(),
terminal.getMerchantId(),
terminal.getMerchantName1(),
terminal.getMerchantName2(),
terminal.getMerchantName3(),
userSessionSource.getUserSession().getUser().getLoginLowerCase(),
tenantId
};
logger.info("terminal_profiling({},{},{},{},{},{},{},{},{},{},{},{},{},{})",
terminal.getSn(),
terminal.getImei(),
terminal.getModelName(),
terminal.getMerchantName(),
terminal.getProfileName(),
terminal.getGroupNames(),
terminal.getTemplateTerminalId(),
terminal.getTerminalId(),
terminal.getMerchantId(),
terminal.getMerchantName1(),
terminal.getMerchantName2(),
terminal.getMerchantName3(),
userSessionSource.getUserSession().getUser().getLoginLowerCase(),
tenantId);
int[] types = new int[] {
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR,
Types.VARCHAR
};
QueryRunner runner = new QueryRunner(persistence.getDataSource());
try {
String[] datas = runner.query(query,
params,
types,
new ResultSetHandler<String[]>() {
@Nullable
@Override
public String[] handle(ResultSet rs) throws SQLException {
if(rs.next()) {
String[] ret = new String[2];
ret[0] = rs.getString(1);
ret[1] = rs.getString(2);
return ret;
}
return null;
}
});
return datas;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean updateTerminal(TerminalExt terminal) throws Exception {
log.info("Saving terminal ...");
Transaction tx = persistence.createTransaction();
try {
dataManager.commit(terminal);
tx.commit();
return true;
} catch(Exception ex) {
throw ex;
} finally {
log.info("Saving terminal DONE");
}
}
private void _parseTerminalsFromFile2(Workbook workbook, Sheet sheet, List<TerminalImportBean> terminals) throws Exception {
{
metadata = AppBeans.get(Metadata.NAME);
terminalAttributesToColumns = createTerminalAttributesToColumns();
// read the values
firstDataRowIndex = 2;
try {
for (currentRowIndex = firstDataRowIndex; !eofTerminal(sheet.getRow(currentRowIndex)); currentRowIndex += dataRowIncrement) {
Row row = sheet.getRow(currentRowIndex);
String sn = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(SN)));
if(sn != null) {
sn = sn.toUpperCase();
}
String imei = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(IMEI))));
if(imei != null) {
imei = imei.toUpperCase();
}
String modelName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MODEL_NAME))));
String merchantName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME))));
String profileName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(PROFILE_NAME))));
String _groupNames = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(GROUP_NAMES))));
String templateTerminalId = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TEMPLATE_TERMINAL_ID))));
String terminalId = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TERMINAL_ID)));
String merchantId = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_ID)));
String merchantName1 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME1))));
String merchantName2 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME2))));
String merchantName3 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME3))));
String merchantName4 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME4))));
String merchantName5 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME5))));
TerminalImportBean terminal = new TerminalImportBean();
terminal.setSn(sn);
terminal.setImei(imei);
terminal.setModelName(modelName);
terminal.setMerchantName(merchantName);
terminal.setProfileName(profileName);
terminal.setGroupNames(_groupNames);
terminal.setTemplateTerminalId(templateTerminalId);
terminal.setTerminalId(terminalId);
terminal.setMerchantId(merchantId);
terminal.setMerchantName1(merchantName1);
terminal.setMerchantName2(merchantName2);
terminal.setMerchantName3(merchantName3);
terminal.setMerchantName4(merchantName4);
terminal.setMerchantName5(merchantName5);
// add to terminal links
terminals.add(terminal);
}
} catch (ImportFileEofEvaluationException e) {
throw new RuntimeException(e);
}
}
}
private void _parseProfilingItemsFromFile(Workbook workbook, Sheet sheet, List<TerminalProfilingItem> items) throws Exception {
{
metadata = AppBeans.get(Metadata.NAME);
terminalAttributesToColumns = createTerminalAttributesToColumns();
// read the values
firstDataRowIndex = 2;
try {
for (currentRowIndex = firstDataRowIndex; !eofTerminal(sheet.getRow(currentRowIndex)); currentRowIndex += dataRowIncrement) {
Row row = sheet.getRow(currentRowIndex);
String sn = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(SN)));
if(sn != null) {
sn = sn.toUpperCase();
}
String imei = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(IMEI))));
if(imei != null) {
imei = imei.toUpperCase();
}
String modelName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MODEL_NAME))));
String merchantName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME))));
String profileName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(PROFILE_NAME))));
String _groupNames = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(GROUP_NAMES))));
String templateTerminalId = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TEMPLATE_TERMINAL_ID))));
String terminalId = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TERMINAL_ID)));
String merchantId = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_ID)));
String merchantName1 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME1))));
String merchantName2 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME2))));
String merchantName3 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME3))));
TerminalProfilingItem item = new TerminalProfilingItem();
item.setSn(sn);
item.setImei(imei);
item.setModelName(modelName);
item.setMerchantName(merchantName);
item.setProfileName(profileName);
item.setGroupNames(_groupNames);
item.setTerminalIdTemplate(templateTerminalId);
item.setTerminalId(terminalId);
item.setMerchantId(merchantId);
item.setMerchantName1(merchantName1);
item.setMerchantName2(merchantName2);
item.setMerchantName3(merchantName3);
// add to item links
items.add(item);
}
} catch (ImportFileEofEvaluationException e) {
throw new RuntimeException(e);
}
}
}
private void _parseTerminalsFromFile(Workbook workbook, Sheet sheet, List<TerminalLink> terminalLinks) throws Exception {
{
/*
metadata = AppBeans.get(Metadata.NAME);
terminalAttributesToColumns = createTerminalAttributesToColumns();
// read the values
firstDataRowIndex = 2;
try {
for (currentRowIndex = firstDataRowIndex; !eofTerminal(sheet.getRow(currentRowIndex)); currentRowIndex += dataRowIncrement) {
Row row = sheet.getRow(currentRowIndex);
String sn = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(SN)));
if(sn != null) {
sn = sn.toUpperCase();
}
String imei = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(IMEI))));
if(imei != null) {
imei = imei.toUpperCase();
}
String modelName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MODEL_NAME))));
String merchantName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME))));
String profileName = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(PROFILE_NAME))));
String _groupNames = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(GROUP_NAMES))));
String[] groupNames = new String[] {};
if(_groupNames != null && !"".equals(_groupNames)) {
groupNames = _groupNames.split(";");
}
String templateTerminalId = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TEMPLATE_TERMINAL_ID))));
String terminalId = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(TERMINAL_ID)));
String merchantId = (String) XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_ID)));
String merchantName1 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME1))));
String merchantName2 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME2))));
String merchantName3 = (String) (XlsHelper.getCellValue(row.getCell(terminalAttributesToColumns.get(MERCHANT_NAME3))));
// fetch model
DeviceModel model = loadDeviceModelByName(modelName);
// fetch merchant
Merchant merchant = loadMerchantByName(merchantName);
// fetch profile
DeviceProfile profile = loadDeviceProfileByName(profileName);
// fetch groups
List<TerminalGroup> groups = new ArrayList<>();
for(String groupName : groupNames) {
if("".equals(groupName.trim())) continue;
groups.add(loadTerminalGroupByName(groupName.trim()));
}
// terminal template
log.info("Template Terminal ID: " + templateTerminalId);
TerminalExt templateTerminal = terminalTemplateCaches.get(templateTerminalId);
if(templateTerminal == null) {
templateTerminal = loadTerminalExtByTerminalId(templateTerminalId);
terminalTemplateCaches.put(templateTerminalId, templateTerminal);
}
log.info("Template Terminal: " + templateTerminal);
List<Acquirer> templateAcquirers = templateTerminal.getAcquirers();
// cache of issuer's cards
LoadContext<Card> loadContext = LoadContext.create(Card.class);
LoadContext<Issuer> issLoadContext = LoadContext.create(Issuer.class);
for(Acquirer oldAcquirer : templateTerminal.getAcquirers()) {
for(Issuer _oldIssuer : oldAcquirer.getIssuers()) {
issLoadContext.setId(_oldIssuer.getId());
issLoadContext.setView("issuer-view");
Issuer oldIssuer = dataManager.load(issLoadContext);
List<Card> theCards = new ArrayList<>();
for(Card _card : oldIssuer.getCards()) {
loadContext.setView("card-view");
loadContext.setId(_card.getId());
Card card = dataManager.load(loadContext);
theCards.add(card);
}
issuerCards.put(oldIssuer.getId(), theCards);
}
}
// terminal link
TerminalLink link = metadata.create(TerminalLink.class);
// terminal
Terminal terminal = metadata.create(Terminal.class);
terminal.setSn(sn);
terminal.setImei(imei);
terminal.setGroup(groups);
terminal.setModel(model);
terminal.setProfile(profile);
terminal.setMerchant(merchant);
TerminalExt terminalExt = metadataTools.deepCopy(templateTerminal);
terminalExt.setId(uuidSource.createUuid());
terminalExt.setTerminalId(terminalId);
terminalExt.setMerchantId(merchantId);
terminalExt.setMerchantName1(merchantName1);
terminalExt.setMerchantName2(merchantName2);
terminalExt.setMerchantName3(merchantName3);
link.setTerminal(terminal);
link.setTerminalExt(terminalExt);
terminalExt.getAcquirers().clear();
// acquirers
List<Acquirer> acquirers = new ArrayList<>();
templateAcquirers.forEach(_acquirer -> {
Acquirer acquirer = metadataTools.deepCopy(_acquirer);
acquirer.setId(uuidSource.createUuid());
acquirer.setAcquirerType(_acquirer.getAcquirerType());
acquirer.setTerminalID(terminalId);
acquirer.setMerchantID(merchantId);
acquirer.setTleSetting(_acquirer.getTleSetting());
acquirer.getIssuers().clear();
acquirers.add(acquirer);
// issuers
List<Issuer> templateIssuers = _acquirer.getIssuers();
List<Issuer> issuers = new ArrayList<>();
templateIssuers.forEach(_issuer -> {
Issuer issuer = metadataTools.deepCopy(_issuer);
issuer.setId(uuidSource.createUuid());
issuer.setOnUs(_issuer.getOnUs());
issuers.add(issuer);
issuer.getCards().clear();
issuerIds.put(issuer.getId(), _issuer.getId());
});
acquirer.setIssuers(issuers);
});
terminalExt.setAcquirers(acquirers);
// add to terminal links
terminalLinks.add(link);
}
} catch (ImportFileEofEvaluationException e) {
throw new RuntimeException(e);
}*/
}
}
private void _parseTerminalsFromEditFile(Workbook workbook, Sheet sheet, List<TerminalExt> terminals) throws Exception {
{
metadata = AppBeans.get(Metadata.NAME);
terminalEditAttributesToColumns = createEditTerminalAttributesToColumns();
// read the values
firstDataRowIndex = 2;
try {
for (currentRowIndex = firstDataRowIndex; !eofEditTerminal(sheet.getRow(currentRowIndex)); currentRowIndex += dataRowIncrement) {
Row row = sheet.getRow(currentRowIndex);
String terminalId = (String) XlsHelper.getCellValue(row.getCell(terminalEditAttributesToColumns.get(TERMINAL_ID)));
String merchantName1 = (String) (XlsHelper.getCellValue(row.getCell(terminalEditAttributesToColumns.get(MERCHANT_NAME1))));
String merchantName2 = (String) (XlsHelper.getCellValue(row.getCell(terminalEditAttributesToColumns.get(MERCHANT_NAME2))));
String merchantName3 = (String) (XlsHelper.getCellValue(row.getCell(terminalEditAttributesToColumns.get(MERCHANT_NAME3))));
// load existing terminal
log.info("Terminal ID: " + terminalId);
TerminalExt terminalExt = loadMinimumTerminalExtByTerminalId(terminalId);
log.info("Terminal Ext: " + terminalExt);
terminalExt.setMerchantName1(merchantName1);
terminalExt.setMerchantName2(merchantName2);
terminalExt.setMerchantName3(merchantName3);
// add to terminals
terminals.add(terminalExt);
}
} catch (ImportFileEofEvaluationException e) {
throw new RuntimeException(e);
}
}
}
public void saveTerminals(List<TerminalLink> terminalLinks) throws Exception {
log.info("Saving terminal links ...");
/*
Transaction tx = persistence.createTransaction();
try {
// prepare commit context
CommitContext commitContext = new CommitContext();
terminalLinks.forEach(terminalLink -> {
// Terminal
Terminal terminal = terminalLink.getTerminal();
// Terminal Ext
TerminalExt terminalExt = terminalLink.getTerminalExt();
// Order of saving
// 1. Terminal
// 2. Terminal Ext
// 3. Acquirers
// 4. Issuers + Link Card
commitContext.addInstanceToCommit(terminal);
commitContext.addInstanceToCommit(terminalExt);
terminalExt.getAcquirers().forEach(acquirer -> {
log.info(">>>> Acquirer#id: " + acquirer.getId() + " (" + acquirer.getName() + ")");
acquirer.setTerminalExt(terminalExt);
commitContext.addInstanceToCommit(acquirer);
acquirer.getIssuers().forEach(issuer -> {
issuer.setAcquirer(acquirer);
log.info(">>>> Issuer#id: " + issuer.getId() + " (" + issuer.getName() + ")");
commitContext.addInstanceToCommit(issuer);
});
});
commitContext.addInstanceToCommit(terminalLink);
dataManager.commit(commitContext);
commitContext.getCommitInstances().clear();
// last one save cards
LoadContext<Issuer> issLoadContext = LoadContext.create(Issuer.class);
terminalExt.getAcquirers().forEach(acquirer -> {
acquirer.getIssuers().forEach(_issuer -> {
issLoadContext.setId(_issuer.getId());
issLoadContext.setView("issuer-view");
Issuer issuer = dataManager.load(issLoadContext);
UUID oldIssuerId = issuerIds.get(_issuer.getId());
List<Card> oldCards = issuerCards.get(oldIssuerId);
List<Card> cards = new ArrayList<>();
for(Card _card : oldCards) {
cards.add(_card);
}
issuer.setCards(cards);
System.out.println("TOTAL CARDS: " + issuer.getCards().size());
//commitContext.addInstanceToCommit(issuer);
dataManager.commit(issuer);
});
});
//dataManager.commit(commitContext);
});
tx.commit();
} finally {
log.info("Saving terminal links DONE");
}*/
}
private Boolean eofByColumnNullValueTerminal(Row row, String columnAlias) throws ImportFileEofEvaluationException {
Integer columnNumber = terminalAttributesToColumns.get(columnAlias);
if (row != null) {
Cell cell = row.getCell(columnNumber);
Object cellValue;
try {
cellValue = XlsHelper.getCellValue(cell);
} catch (Exception e) {
throw new ImportFileEofEvaluationException(String.format("Eof evaluation has failed on row %s", row.getRowNum()));
}
return cellValue == null;
}
return true;
}
private Boolean eofByColumnNullValueEditTerminal(Row row, String columnAlias) throws ImportFileEofEvaluationException {
Integer columnNumber = terminalEditAttributesToColumns.get(columnAlias);
if (row != null) {
Cell cell = row.getCell(columnNumber);
Object cellValue;
try {
cellValue = XlsHelper.getCellValue(cell);
} catch (Exception e) {
throw new ImportFileEofEvaluationException(String.format("Eof evaluation has failed on row %s", row.getRowNum()));
}
return cellValue == null;
}
return true;
}
private Map<String, Integer> createTerminalAttributesToColumns() {
Map<String, Integer> columns = new HashMap<>();
columns.put(SN, 0);
columns.put(IMEI, 1);
columns.put(MODEL_NAME, 2);
columns.put(MERCHANT_NAME, 3);
columns.put(PROFILE_NAME, 4);
columns.put(GROUP_NAMES, 5);
columns.put(TEMPLATE_TERMINAL_ID, 6);
columns.put(TERMINAL_ID, 7);
columns.put(MERCHANT_ID, 8);
columns.put(MERCHANT_NAME1, 9);
columns.put(MERCHANT_NAME2, 10);
columns.put(MERCHANT_NAME3, 11);
columns.put(MERCHANT_NAME4, 12);
columns.put(MERCHANT_NAME5, 13);
return columns;
}
private Map<String, Integer> createEditTerminalAttributesToColumns() {
Map<String, Integer> columns = new HashMap<>();
columns.put(TERMINAL_ID, 0);
columns.put(MERCHANT_NAME1, 1);
columns.put(MERCHANT_NAME2, 2);
columns.put(MERCHANT_NAME3, 3);
return columns;
}
protected boolean eofTerminal(Row row) throws ImportFileEofEvaluationException {
return eofByColumnNullValueTerminal(row, SN);
}
protected boolean eofEditTerminal(Row row) throws ImportFileEofEvaluationException {
return eofByColumnNullValueEditTerminal(row, SN);
}
protected boolean eofProfile(Row row) throws ImportFileEofEvaluationException {
int maxRow = SpreadsheetVersion.EXCEL97.getLastRowIndex();
//return eofByColumnNullValueProfile(row, PROFILE_CODE);
return row == null || row.getRowNum() > maxRow;
}
private DeviceProfile loadDeviceProfileByName(String profileName) {
LoadContext<DeviceProfile> loadContext = LoadContext.create(DeviceProfile.class);
loadContext.setQueryString("select m from tms_DeviceProfile m where lower(m.name)=:name and m.deleteTs is null");
loadContext.getQuery().setParameter("name", profileName.toLowerCase());
loadContext.setView("deviceProfile-minimal-view");
DeviceProfile profile = dataManager.load(loadContext);
return profile;
}
private DeviceModel loadDeviceModelByName(String modelName) {
LoadContext<DeviceModel> loadContext = LoadContext.create(DeviceModel.class);
loadContext.setQueryString("select m from tms_DeviceModel m where lower(m.model)=:name and m.deleteTs is null");
loadContext.getQuery().setParameter("name", modelName.toLowerCase());
loadContext.setView("deviceModel-minimal-view");
DeviceModel model = dataManager.load(loadContext);
return model;
}
private Merchant loadMerchantByName(String merchantName) {
LoadContext<Merchant> loadContext = LoadContext.create(Merchant.class);
loadContext.setQueryString("select m from tms_Merchant m where lower(m.name)=:name and m.deleteTs is null");
loadContext.getQuery().setParameter("name", merchantName.toLowerCase());
loadContext.setView("merchant-minimal-view");
Merchant merchant = dataManager.load(loadContext);
return merchant;
}
private TerminalGroup loadTerminalGroupByName(String groupName) {
LoadContext<TerminalGroup> loadContext = LoadContext.create(TerminalGroup.class);
loadContext.setQueryString("select m from tms_TerminalGroup m where lower(m.name)=:name and m.deleteTs is null");
loadContext.getQuery().setParameter("name", groupName.toLowerCase());
loadContext.setView("terminalGroup-view");
TerminalGroup terminalGroup = dataManager.load(loadContext);
return terminalGroup;
}
private TerminalExt loadTerminalExtByTerminalId(String terminalID) {
LoadContext<TerminalExt> loadContext = LoadContext.create(TerminalExt.class);
loadContext.setQueryString("select m from tms$TerminalExt m where m.terminalId=:terminalId and m.deleteTs is null");
loadContext.getQuery().setParameter("terminalId", terminalID);
loadContext.setView("terminalExt-full-view");
TerminalExt terminal = dataManager.load(loadContext);
return terminal;
}
private TerminalExt loadMinimumTerminalExtByTerminalId(String terminalID) {
LoadContext<TerminalExt> loadContext = LoadContext.create(TerminalExt.class);
loadContext.setQueryString("select m from tms$TerminalExt m where m.terminalId=:terminalId and m.deleteTs is null");
loadContext.getQuery().setParameter("terminalId", terminalID);
loadContext.setView("terminalExt-minimal2-view");
TerminalExt terminal = dataManager.load(loadContext);
return terminal;
}
}

View File

@ -0,0 +1,80 @@
package com.cmobile.unifiedtms.service;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.TerminalLink;
import com.cmobile.unifiedtms.entity.restmodel.result.data.Feature;
import com.cmobile.unifiedtms.entity.restmodel.result.data.TerminalFeatures;
import com.cmobile.unifiedtms.ext.entity.TerminalExt;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Messages;
import com.haulmont.cuba.core.global.Metadata;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Service(TerminalService.NAME)
public class TerminalServiceBean implements TerminalService {
@Inject
private DataManager dataManager;
@Inject
private Messages messages;
@Inject
private Logger logger;
@Inject
private Metadata metadata;
@Override
public TerminalFeatures getTerminalByTid(String tid) {
LoadContext<TerminalLink> loadContextTerminalLink = LoadContext.create(TerminalLink.class);
loadContextTerminalLink.setQueryString("select t from tms_TerminalLink t where t.terminalExt.terminalId=:terminalId");
loadContextTerminalLink.getQuery().setParameter("terminalId", tid);
loadContextTerminalLink.setView("terminalLink-local-view");
TerminalLink terminalLink = dataManager.load(loadContextTerminalLink);
if(terminalLink != null) {
Terminal terminal = terminalLink.getTerminal();
TerminalExt terminalExt = terminalLink.getTerminalExt();
TerminalFeatures terminalFeatures = new TerminalFeatures();
terminalFeatures.setSn(terminal.getSn());
terminalFeatures.setImei(terminal.getImei());
terminalFeatures.setTerminalId(terminalExt.getTerminalId());
terminalFeatures.setProvider(terminal.getCellName());
terminalFeatures.setAppVersion(terminal.getVfssVersion());
terminalFeatures.setLatitude(terminal.getLatitude());
terminalFeatures.setLongitude(terminal.getLongitude());
List<Feature> features = new ArrayList<>();
List<Field> allFields = Arrays.asList(TerminalExt.class.getDeclaredFields());
allFields.forEach(field -> {
field.setAccessible(true);
String fieldName = field.getName();
if(fieldName.startsWith("feature")) {
try {
String label = messages.getMessage("com.cmobile.unifiedtms.ext.entity", "TerminalExt." + fieldName);
Boolean value = (Boolean) field.get(terminalExt);
features.add(new Feature(label, booleanValue(value)));
} catch(IllegalAccessException iaex) {
logger.error("Error getting field value: {}", fieldName, iaex);
}
}
});
terminalFeatures.setFeatureTransactions(features);
return terminalFeatures;
} else {
// tid not found or not linked yet
return null;
}
}
private boolean booleanValue(Boolean val) {
return val != null ? val.booleanValue() : false;
}
}

View File

@ -0,0 +1,82 @@
package com.cmobile.unifiedtms.service.controllers;
import com.cmobile.unifiedtms.entity.Terminal;
import com.cmobile.unifiedtms.entity.TerminalLink;
import com.cmobile.unifiedtms.entity.restmodel.result.data.Feature;
import com.cmobile.unifiedtms.entity.restmodel.result.data.TerminalFeatures;
import com.cmobile.unifiedtms.ext.entity.TerminalExt;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.LoadContext;
import com.haulmont.cuba.core.global.Messages;
import com.haulmont.cuba.core.global.Metadata;
import org.slf4j.Logger;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.inject.Inject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RestController
public class TerminalController {
@Inject
private DataManager dataManager;
@Inject
private Messages messages;
@Inject
private Logger logger;
@Inject
private Metadata metadata;
@GetMapping("/terminal/{tid}")
public ResponseEntity<Object> getTerminal(
@PathVariable("tid") String tid
) {
LoadContext<TerminalLink> loadContextTerminalLink = LoadContext.create(TerminalLink.class);
loadContextTerminalLink.setQueryString("select t from tms_TerminalLink t where t.terminalExt.terminalId=:terminalId");
loadContextTerminalLink.getQuery().setParameter("terminalId", tid);
loadContextTerminalLink.setView("terminalLink-local-view");
TerminalLink terminalLink = dataManager.load(loadContextTerminalLink);
if(terminalLink != null) {
Terminal terminal = terminalLink.getTerminal();
TerminalExt terminalExt = terminalLink.getTerminalExt();
TerminalFeatures terminalFeatures = new TerminalFeatures();
terminalFeatures.setSn(terminal.getSn());
terminalFeatures.setImei(terminal.getImei());
terminalFeatures.setTerminalId(terminalExt.getTerminalId());
terminalFeatures.setProvider(terminal.getCellName());
terminalFeatures.setAppVersion(terminal.getVfssVersion());
List<Feature> features = new ArrayList<>();
List<Field> allFields = Arrays.asList(TerminalExt.class.getDeclaredFields());
allFields.forEach(field -> {
String fieldName = field.getName();
if(fieldName.startsWith("feature")) {
try {
Boolean value = (Boolean) field.get(terminalExt);
features.add(new Feature(fieldName, booleanValue(value)));
} catch(IllegalAccessException iaex) {
logger.error("Error getting field value: {}", fieldName, iaex);
}
}
});
terminalFeatures.setFeatureTransactions(features);
return ResponseEntity.ok(terminalFeatures);
} else {
// tid not found or not linked yet
return ResponseEntity.notFound().build();
}
}
private boolean booleanValue(Boolean val) {
return val != null ? val.booleanValue() : false;
}
}

View File

@ -0,0 +1,9 @@
rest-messages.success=Success
rest-messages.failure=Failure
rest-messages.not-found=Data Not Found
rest-messages.already-exists=Already Exists
rest-messages.not-contained=Not Contained
rest-messages.invalid-file=Invalid File
rest-messages.invalid-params=Invalid Params
rest-messages.not-linked=Not Linked
rest-messages.general-error=System Exception Error

View File

@ -0,0 +1,9 @@
rest-messages.success=Sukses
rest-messages.failure=Gagal
rest-messages.not-found=Data Tidak Ditemukan
rest-messages.already-exists=Sudah Ada
rest-messages.not-contained=Tidak Termasuk
rest-messages.invalid-file=File Tidak Valid
rest-messages.invalid-params=Parameter Tidak Valid
rest-messages.not-linked=Tidak Disambungkan
rest-messages.general-error=Error Sistem

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context">
<!-- Annotation-based beans -->
<context:component-scan base-package="com.cmobile.unifiedtms"/>
</beans>

View File

@ -0,0 +1,32 @@
package com.cmobile.unifiedtms.utils;
public final class ISOUtil {
public static byte[] hex2byte(byte[] b, int offset, int len) {
byte[] d = new byte[len];
for (int i = 0; i < len * 2; i++) {
int shift = (i % 2 == 1) ? 0 : 4;
d[i >> 1] = (byte)(d[i >> 1] | Character.digit((char)b[offset + i], 16) << shift);
}
return d;
}
public static byte[] hex2byte(String s) {
if (s.length() % 2 == 0) {
return hex2byte(s.getBytes(), 0, s.length() >> 1);
}
throw new RuntimeException("Uneven number(" + s.length() + ") of hex digits passed to hex2byte.");
}
public static String hexString(byte[] b) {
StringBuilder d = new StringBuilder(b.length * 2);
for (int i = 0; i < b.length; i++) {
char hi = Character.forDigit(b[i] >> 4 & 0xF, 16);
char lo = Character.forDigit(b[i] & 0xF, 16);
d.append(Character.toUpperCase(hi));
d.append(Character.toUpperCase(lo));
}
return d.toString();
}
}

View File

@ -0,0 +1,85 @@
package com.cmobile.unifiedtms.utils;
import com.cmobile.unifiedtms.entity.misc.TerminalUpdateCacheObj;
import com.drew.metadata.mov.atoms.Atom;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
public class TerminalUpdateCache {
private Map<String, TerminalUpdateCacheObj> caches = new LinkedHashMap<>();
private long considerDonePeriod = (10 * 60 * 1000); // 10 minutes
private long releaseFromCachePeriod = 3 * 24 * 60 * 60 * 1000; // 3 days
private int partialCapacity = 1000;
private AtomicInteger currentCapacity = new AtomicInteger(0); // started & ongoing status
public TerminalUpdateCache() {}
public void setCapacity(int capacity) {
this.partialCapacity = capacity;
}
public int put(String key, TerminalUpdateCacheObj obj) {
this.caches.put(key, obj);
return this.currentCapacity.incrementAndGet();
}
// update to finished status
public int updateToFinished(String key, TerminalUpdateCacheObj obj) {
this.caches.put(key, obj);
return this.currentCapacity.decrementAndGet();
}
public TerminalUpdateCacheObj get(String key) {
return this.caches.get(key);
}
public boolean isFull() {
return this.currentCapacity.get() >= this.partialCapacity;//this.currentCapacity.get() >= this.partialCapacity;
}
public void runUpdateStatus() {
Set<Map.Entry<String, TerminalUpdateCacheObj>> entrySet = this.caches.entrySet();
entrySet.forEach(entry -> {
TerminalUpdateCacheObj obj = entry.getValue();
Date createdTime = obj.getCreatedTime();
long now = System.currentTimeMillis();
long elapsed = createdTime.getTime() - now;
// if still ongoing status
if("Ongoing".equalsIgnoreCase(obj.getStatus())) {
if(elapsed >= considerDonePeriod) {
obj.considerDone();
this.updateToFinished(entry.getKey(), obj);
}
}
});
}
public void cleanupCache() {
Set<Map.Entry<String, TerminalUpdateCacheObj>> entrySet = this.caches.entrySet();
entrySet.forEach(entry -> {
TerminalUpdateCacheObj obj = entry.getValue();
Date createdTime = obj.getCreatedTime();
long now = System.currentTimeMillis();
long elapsed = createdTime.getTime() - now;
// if still ongoing status
if("Finished".equalsIgnoreCase(obj.getStatus())) {
if(elapsed >= releaseFromCachePeriod) {
this.caches.remove(entry.getKey());
}
}
});
}
public Map<String, TerminalUpdateCacheObj> getCaches() {
return caches;
}
public AtomicInteger getCurrentCapacity() {
return currentCapacity;
}
}

View File

@ -0,0 +1,175 @@
package com.cmobile.unifiedtms.utils;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.Resources;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Created by aleksey on 18/10/2016.
*
* Class helping to work with .xls and .xlsx files
*
*/
public class XlsHelper {
protected static final char NON_BREAKING_SPACE = (char) 160;
protected static Resources resources = AppBeans.get(Resources.NAME);
/**
* Method returns workbook for .xls and .xlsx files
*/
@Nullable
public static Workbook openWorkbook(@Nullable String path) throws IOException {
Workbook workbook = null;
InputStream is = resources.getResourceAsStream(path);
String extension = FilenameUtils.getExtension(path);
if (is != null) {
if ("xls".equals(extension)) {
workbook = new HSSFWorkbook(is);
} else if ("xlsx".equals(extension)) {
workbook = new XSSFWorkbook(is);
}
is.close();
}
return workbook;
}
public static Workbook openWorkbook(byte[] bytes) throws IOException {
Workbook workbook;
try {
InputStream is = new ByteArrayInputStream(bytes);
workbook = new HSSFWorkbook(new POIFSFileSystem(is));
is.close();
} catch (OfficeXmlFileException exc) {
InputStream is = new ByteArrayInputStream(bytes);
workbook = new XSSFWorkbook(is);
is.close();
}
return workbook;
}
@Nullable
public static Object getCellValue(Cell cell) throws Exception {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case BLANK:
return null;
case STRING:
String formattedCellValue = cell.getStringCellValue().replace(String.valueOf(NON_BREAKING_SPACE), " ").trim();
return formattedCellValue.isEmpty() ? null : formattedCellValue;
case NUMERIC:
if (isDateCell(cell)) {
return cell.getDateCellValue();
}
Double numericCellValue = cell.getNumericCellValue();
if (!isAlmostInt(numericCellValue))
return numericCellValue;
else {
if (numericCellValue > Integer.MAX_VALUE) {
Long value = numericCellValue.longValue();
return value;
} else {
Integer value = numericCellValue.intValue();
return value;
}
}
case FORMULA:
return getFormulaCellValue(cell);
default:
throw new IllegalStateException(String.format("Cell type '%s' is not supported", cell.getCellType()));
}
}
protected static boolean isDateCell(Cell cell) {
return HSSFDateUtil.isCellDateFormatted(cell);
}
protected static boolean isAlmostInt(Double numericCellValue) {
return Math.abs(numericCellValue - numericCellValue.longValue()) < 1e-10;
}
protected static Object getFormulaCellValue(Cell cell) {
String formattedCellValue;
try {
formattedCellValue = cell.getStringCellValue().replace(String.valueOf(NON_BREAKING_SPACE), " ").trim();
} catch (IllegalStateException e) {
return "Formula error";
}
switch (cell.getCachedFormulaResultType()) {
case NUMERIC:
return cell.getNumericCellValue();
case STRING:
if (formattedCellValue.isEmpty())
return null;
return formattedCellValue;
default:
throw new IllegalStateException(String.format("Formula cell type '%s' is not supported", cell.getCachedFormulaResultType()));
}
}
@Nullable
public static Object getCellValue(Cell cell, Boolean forceToString) throws Exception {
if (cell == null || cell.getCellType() == CellType.BLANK) {
return null;
}
cell.setCellType(CellType.STRING);
return cell.getStringCellValue().replace(String.valueOf(NON_BREAKING_SPACE), " ").trim();
}
@Nullable
public static <T extends Object> T getParameterValue(Map<String, Object> values, String parameter) {
if (values.get(parameter) == null) {
return null;
}
return (T) values.get(parameter);
}
@Nullable
public static Double getParameterDoubleValue(Map<String, Object> values, String parameter) {
if (values.get(parameter) == null) {
return null;
}
return Double.valueOf(values.get(parameter).toString());
}
@Nullable
public static Integer getParameterIntegerValue(Map<String, Object> values, String parameter) {
Object value = values.get(parameter);
if (value == null) {
return null;
}
if (value instanceof Number)
return ((Number) value).intValue();
return Integer.valueOf(value.toString());
}
@Nullable
public static String getParameterStringValue(Map<String, Object> values, String parameter) {
if (values.get(parameter) == null) {
return null;
}
return values.get(parameter).toString().trim();
}
}

View File

@ -0,0 +1,240 @@
package sasc.emv;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.LinkedHashMap;
import sasc.iso7816.Tag;
import sasc.iso7816.TagImpl;
import sasc.iso7816.TagValueType;
import sasc.util.ByteArrayWrapper;
import sasc.util.Util;
public class EMVTags {
private static LinkedHashMap<IssuerIdentificationNumber, LinkedHashMap<ByteArrayWrapper, Tag>> issuerToTagsMap = new LinkedHashMap();
private static LinkedHashMap<ByteArrayWrapper, LinkedHashMap<ByteArrayWrapper, Tag>> paymentSystemToTagsMap = new LinkedHashMap();
private static LinkedHashMap<ByteArrayWrapper, Tag> tags = new LinkedHashMap();
public static final Tag UNIVERSAL_TAG_FOR_OID = new TagImpl("06", TagValueType.BINARY, "Object Identifier (OID)", "Universal tag for OID");
public static final Tag COUNTRY_CODE = new TagImpl("41", TagValueType.NUMERIC, "Country Code", "Country code (encoding specified in ISO 3166-1) and optional national data");
public static final Tag ISSUER_IDENTIFICATION_NUMBER = new TagImpl("42", TagValueType.NUMERIC, "Issuer Identification Number (IIN)", "The number that identifies the major industry and the card issuer and that forms the first part of the Primary Account Number (PAN)");
public static final Tag AID_CARD = new TagImpl("4f", TagValueType.BINARY, "Application Identifier (AID) - card", "Identifies the application as described in ISO/IEC 7816-5");
public static final Tag APPLICATION_LABEL = new TagImpl("50", TagValueType.TEXT, "Application Label", "Mnemonic associated with the AID according to ISO/IEC 7816-5");
public static final Tag PATH = new TagImpl("51", TagValueType.BINARY, "File reference data element", "ISO-7816 Path");
public static final Tag COMMAND_APDU = new TagImpl("52", TagValueType.BINARY, "Command APDU", "");
public static final Tag DISCRETIONARY_DATA_OR_TEMPLATE = new TagImpl("53", TagValueType.BINARY, "Discretionary data (or template)", "");
public static final Tag APPLICATION_TEMPLATE = new TagImpl("61", TagValueType.BINARY, "Application Template", "Contains one or more data objects relevant to an application directory entry according to ISO/IEC 7816-5");
public static final Tag FCI_TEMPLATE = new TagImpl("6f", TagValueType.BINARY, "File Control Information (FCI) Template", "Set of file control parameters and file management data (according to ISO/IEC 7816-4)");
public static final Tag DD_TEMPLATE = new TagImpl("73", TagValueType.BINARY, "Directory Discretionary Template", "Issuer discretionary part of the directory according to ISO/IEC 7816-5");
public static final Tag DEDICATED_FILE_NAME = new TagImpl("84", TagValueType.BINARY, "Dedicated File (DF) Name", "Identifies the name of the DF as described in ISO/IEC 7816-4");
public static final Tag SFI = new TagImpl("88", TagValueType.BINARY, "Short File Identifier (SFI)", "Identifies the SFI to be used in the commands related to a given AEF or DDF. The SFI data object is a binary field with the three high order bits set to zero");
public static final Tag FCI_PROPRIETARY_TEMPLATE = new TagImpl("a5", TagValueType.BINARY, "File Control Information (FCI) Proprietary Template", "Identifies the data object proprietary to this specification in the FCI template according to ISO/IEC 7816-4");
public static final Tag ISSUER_URL = new TagImpl("5f50", TagValueType.TEXT, "Issuer URL", "The URL provides the location of the Issuers Library Server on the Internet");
public static final Tag TRACK_2_EQV_DATA = new TagImpl("57", TagValueType.BINARY, "Track 2 Equivalent Data", "Contains the data elements of track 2 according to ISO/IEC 7813, excluding start sentinel, end sentinel, and Longitudinal Redundancy Check (LRC)");
public static final Tag PAN = new TagImpl("5a", TagValueType.NUMERIC, "Application Primary Account Number (PAN)", "Valid cardholder account number");
public static final Tag RECORD_TEMPLATE = new TagImpl("70", TagValueType.BINARY, "Record Template (EMV Proprietary)", "Template proprietary to the EMV specification");
public static final Tag ISSUER_SCRIPT_TEMPLATE_1 = new TagImpl("71", TagValueType.BINARY, "Issuer Script Template 1", "Contains proprietary issuer data for transmission to the ICC before the second GENERATE AC command");
public static final Tag ISSUER_SCRIPT_TEMPLATE_2 = new TagImpl("72", TagValueType.BINARY, "Issuer Script Template 2", "Contains proprietary issuer data for transmission to the ICC after the second GENERATE AC command");
public static final Tag RESPONSE_MESSAGE_TEMPLATE_2 = new TagImpl("77", TagValueType.BINARY, "Response Message Template Format 2", "Contains the data objects (with tags and lengths) returned by the ICC in response to a command");
public static final Tag RESPONSE_MESSAGE_TEMPLATE_1 = new TagImpl("80", TagValueType.BINARY, "Response Message Template Format 1", "Contains the data objects (without tags and lengths) returned by the ICC in response to a command");
public static final Tag AMOUNT_AUTHORISED_BINARY = new TagImpl("81", TagValueType.BINARY, "Amount, Authorised (Binary)", "Authorised amount of the transaction (excluding adjustments)");
public static final Tag APPLICATION_INTERCHANGE_PROFILE = new TagImpl("82", TagValueType.BINARY, "Application Interchange Profile", "Indicates the capabilities of the card to support specific functions in the application");
public static final Tag COMMAND_TEMPLATE = new TagImpl("83", TagValueType.BINARY, "Command Template", "Identifies the data field of a command message");
public static final Tag ISSUER_SCRIPT_COMMAND = new TagImpl("86", TagValueType.BINARY, "Issuer Script Command", "Contains a command for transmission to the ICC");
public static final Tag APPLICATION_PRIORITY_INDICATOR = new TagImpl("87", TagValueType.BINARY, "Application Priority Indicator", "Indicates the priority of a given application or group of applications in a directory");
public static final Tag AUTHORISATION_CODE = new TagImpl("89", TagValueType.BINARY, "Authorisation Code", "Value generated by the authorisation authority for an approved transaction");
public static final Tag AUTHORISATION_RESPONSE_CODE = new TagImpl("8a", TagValueType.TEXT, "Authorisation Response Code", "Code that defines the disposition of a message");
public static final Tag CDOL1 = new TagImpl("8c", TagValueType.DOL, "Card Risk Management Data Object List 1 (CDOL1)", "List of data objects (tag and length) to be passed to the ICC in the first GENERATE AC command");
public static final Tag CDOL2 = new TagImpl("8d", TagValueType.DOL, "Card Risk Management Data Object List 2 (CDOL2)", "List of data objects (tag and length) to be passed to the ICC in the second GENERATE AC command");
public static final Tag CVM_LIST = new TagImpl("8e", TagValueType.BINARY, "Cardholder Verification Method (CVM) List", "Identifies a method of verification of the cardholder supported by the application");
public static final Tag CA_PUBLIC_KEY_INDEX_CARD = new TagImpl("8f", TagValueType.BINARY, "Certification Authority Public Key Index - card", "Identifies the certification authoritys public key in conjunction with the RID");
public static final Tag ISSUER_PUBLIC_KEY_CERT = new TagImpl("90", TagValueType.BINARY, "Issuer Public Key Certificate", "Issuer public key certified by a certification authority");
public static final Tag ISSUER_AUTHENTICATION_DATA = new TagImpl("91", TagValueType.BINARY, "Issuer Authentication Data", "Data sent to the ICC for online issuer authentication");
public static final Tag ISSUER_PUBLIC_KEY_REMAINDER = new TagImpl("92", TagValueType.BINARY, "Issuer Public Key Remainder", "Remaining digits of the Issuer Public Key Modulus");
public static final Tag SIGNED_STATIC_APP_DATA = new TagImpl("93", TagValueType.BINARY, "Signed Static Application Data", "Digital signature on critical application parameters for SDA");
public static final Tag APPLICATION_FILE_LOCATOR = new TagImpl("94", TagValueType.BINARY, "Application File Locator (AFL)", "Indicates the location (SFI, range of records) of the AEFs related to a given application");
public static final Tag TERMINAL_VERIFICATION_RESULTS = new TagImpl("95", TagValueType.BINARY, "Terminal Verification Results (TVR)", "Status of the different functions as seen from the terminal");
public static final Tag TDOL = new TagImpl("97", TagValueType.BINARY, "Transaction Certificate Data Object List (TDOL)", "List of data objects (tag and length) to be used by the terminal in generating the TC Hash Value");
public static final Tag TC_HASH_VALUE = new TagImpl("98", TagValueType.BINARY, "Transaction Certificate (TC) Hash Value", "Result of a hash function specified in Book 2, Annex B3.1");
public static final Tag TRANSACTION_PIN_DATA = new TagImpl("99", TagValueType.BINARY, "Transaction Personal Identification Number (PIN) Data", "Data entered by the cardholder for the purpose of the PIN verification");
public static final Tag TRANSACTION_DATE = new TagImpl("9a", TagValueType.NUMERIC, "Transaction Date", "Local date that the transaction was authorised");
public static final Tag TRANSACTION_STATUS_INFORMATION = new TagImpl("9b", TagValueType.BINARY, "Transaction Status Information", "Indicates the functions performed in a transaction");
public static final Tag TRANSACTION_TYPE = new TagImpl("9c", TagValueType.NUMERIC, "Transaction Type", "Indicates the type of financial transaction, represented by the first two digits of ISO 8583:1987 Processing Code");
public static final Tag DDF_NAME = new TagImpl("9d", TagValueType.BINARY, "Directory Definition File (DDF) Name", "Identifies the name of a DF associated with a directory");
public static final Tag CARDHOLDER_NAME = new TagImpl("5f20", TagValueType.TEXT, "Cardholder Name", "Indicates cardholder name according to ISO 7813");
public static final Tag APP_EXPIRATION_DATE = new TagImpl("5f24", TagValueType.NUMERIC, "Application Expiration Date", "Date after which application expires");
public static final Tag APP_EFFECTIVE_DATE = new TagImpl("5f25", TagValueType.NUMERIC, "Application Effective Date", "Date from which the application may be used");
public static final Tag ISSUER_COUNTRY_CODE = new TagImpl("5f28", TagValueType.NUMERIC, "Issuer Country Code", "Indicates the country of the issuer according to ISO 3166");
public static final Tag TRANSACTION_CURRENCY_CODE = new TagImpl("5f2a", TagValueType.TEXT, "Transaction Currency Code", "Indicates the currency code of the transaction according to ISO 4217");
public static final Tag LANGUAGE_PREFERENCE = new TagImpl("5f2d", TagValueType.TEXT, "Language Preference", "14 languages stored in order of preference, each represented by 2 alphabetical characters according to ISO 639");
public static final Tag SERVICE_CODE = new TagImpl("5f30", TagValueType.NUMERIC, "Service Code", "Service code as defined in ISO/IEC 7813 for track 1 and track 2");
public static final Tag PAN_SEQUENCE_NUMBER = new TagImpl("5f34", TagValueType.NUMERIC, "Application Primary Account Number (PAN) Sequence Number", "Identifies and differentiates cards with the same PAN");
public static final Tag TRANSACTION_CURRENCY_EXP = new TagImpl("5f36", TagValueType.NUMERIC, "Transaction Currency Exponent", "Indicates the implied position of the decimal point from the right of the transaction amount represented according to ISO 4217");
public static final Tag IBAN = new TagImpl("5f53", TagValueType.BINARY, "International Bank Account Number (IBAN)", "Uniquely identifies the account of a customer at a financial institution as defined in ISO 13616");
public static final Tag BANK_IDENTIFIER_CODE = new TagImpl("5f54", TagValueType.MIXED, "Bank Identifier Code (BIC)", "Uniquely identifies a bank as defined in ISO 9362");
public static final Tag ISSUER_COUNTRY_CODE_ALPHA2 = new TagImpl("5f55", TagValueType.TEXT, "Issuer Country Code (alpha2 format)", "Indicates the country of the issuer as defined in ISO 3166 (using a 2 character alphabetic code)");
public static final Tag ISSUER_COUNTRY_CODE_ALPHA3 = new TagImpl("5f56", TagValueType.TEXT, "Issuer Country Code (alpha3 format)", "Indicates the country of the issuer as defined in ISO 3166 (using a 3 character alphabetic code)");
public static final Tag ACQUIRER_IDENTIFIER = new TagImpl("9f01", TagValueType.NUMERIC, "Acquirer Identifier", "Uniquely identifies the acquirer within each payment system");
public static final Tag AMOUNT_AUTHORISED_NUMERIC = new TagImpl("9f02", TagValueType.NUMERIC, "Amount, Authorised (Numeric)", "Authorised amount of the transaction (excluding adjustments)");
public static final Tag AMOUNT_OTHER_NUMERIC = new TagImpl("9f03", TagValueType.NUMERIC, "Amount, Other (Numeric)", "Secondary amount associated with the transaction representing a cashback amount");
public static final Tag AMOUNT_OTHER_BINARY = new TagImpl("9f04", TagValueType.NUMERIC, "Amount, Other (Binary)", "Secondary amount associated with the transaction representing a cashback amount");
public static final Tag APP_DISCRETIONARY_DATA = new TagImpl("9f05", TagValueType.BINARY, "Application Discretionary Data", "Issuer or payment system specified data relating to the application");
public static final Tag AID_TERMINAL = new TagImpl("9f06", TagValueType.BINARY, "Application Identifier (AID) - terminal", "Identifies the application as described in ISO/IEC 7816-5");
public static final Tag APP_USAGE_CONTROL = new TagImpl("9f07", TagValueType.BINARY, "Application Usage Control", "Indicates issuers specified restrictions on the geographic usage and services allowed for the application");
public static final Tag APP_VERSION_NUMBER_CARD = new TagImpl("9f08", TagValueType.BINARY, "Application Version Number - card", "Version number assigned by the payment system for the application");
public static final Tag APP_VERSION_NUMBER_TERMINAL = new TagImpl("9f09", TagValueType.BINARY, "Application Version Number - terminal", "Version number assigned by the payment system for the application");
public static final Tag CARDHOLDER_NAME_EXTENDED = new TagImpl("9f0b", TagValueType.TEXT, "Cardholder Name Extended", "Indicates the whole cardholder name when greater than 26 characters using the same coding convention as in ISO 7813");
public static final Tag ISSUER_ACTION_CODE_DEFAULT = new TagImpl("9f0d", TagValueType.BINARY, "Issuer Action Code - Default", "Specifies the issuers conditions that cause a transaction to be rejected if it might have been approved online, but the terminal is unable to process the transaction online");
public static final Tag ISSUER_ACTION_CODE_DENIAL = new TagImpl("9f0e", TagValueType.BINARY, "Issuer Action Code - Denial", "Specifies the issuers conditions that cause the denial of a transaction without attempt to go online");
public static final Tag ISSUER_ACTION_CODE_ONLINE = new TagImpl("9f0f", TagValueType.BINARY, "Issuer Action Code - Online", "Specifies the issuers conditions that cause a transaction to be transmitted online");
public static final Tag ISSUER_APPLICATION_DATA = new TagImpl("9f10", TagValueType.BINARY, "Issuer Application Data", "Contains proprietary application data for transmission to the issuer in an online transaction");
public static final Tag ISSUER_CODE_TABLE_INDEX = new TagImpl("9f11", TagValueType.NUMERIC, "Issuer Code Table Index", "Indicates the code table according to ISO/IEC 8859 for displaying the Application Preferred Name");
public static final Tag APP_PREFERRED_NAME = new TagImpl("9f12", TagValueType.TEXT, "Application Preferred Name", "Preferred mnemonic associated with the AID");
public static final Tag LAST_ONLINE_ATC_REGISTER = new TagImpl("9f13", TagValueType.BINARY, "Last Online Application Transaction Counter (ATC) Register", "ATC value of the last transaction that went online");
public static final Tag LOWER_CONSEC_OFFLINE_LIMIT = new TagImpl("9f14", TagValueType.BINARY, "Lower Consecutive Offline Limit", "Issuer-specified preference for the maximum number of consecutive offline transactions for this ICC application allowed in a terminal with online capability");
public static final Tag MERCHANT_CATEGORY_CODE = new TagImpl("9f15", TagValueType.NUMERIC, "Merchant Category Code", "Classifies the type of business being done by the merchant, represented according to ISO 8583:1993 for Card Acceptor Business Code");
public static final Tag MERCHANT_IDENTIFIER = new TagImpl("9f16", TagValueType.TEXT, "Merchant Identifier", "When concatenated with the Acquirer Identifier, uniquely identifies a given merchant");
public static final Tag PIN_TRY_COUNTER = new TagImpl("9f17", TagValueType.BINARY, "Personal Identification Number (PIN) Try Counter", "Number of PIN tries remaining");
public static final Tag ISSUER_SCRIPT_IDENTIFIER = new TagImpl("9f18", TagValueType.BINARY, "Issuer Script Identifier", "Identification of the Issuer Script");
public static final Tag TERMINAL_COUNTRY_CODE = new TagImpl("9f1a", TagValueType.TEXT, "Terminal Country Code", "Indicates the country of the terminal, represented according to ISO 3166");
public static final Tag TERMINAL_FLOOR_LIMIT = new TagImpl("9f1b", TagValueType.BINARY, "Terminal Floor Limit", "Indicates the floor limit in the terminal in conjunction with the AID");
public static final Tag TERMINAL_IDENTIFICATION = new TagImpl("9f1c", TagValueType.TEXT, "Terminal Identification", "Designates the unique location of a terminal at a merchant");
public static final Tag TERMINAL_RISK_MANAGEMENT_DATA = new TagImpl("9f1d", TagValueType.BINARY, "Terminal Risk Management Data", "Application-specific value used by the card for risk management purposes");
public static final Tag INTERFACE_DEVICE_SERIAL_NUMBER = new TagImpl("9f1e", TagValueType.TEXT, "Interface Device (IFD) Serial Number", "Unique and permanent serial number assigned to the IFD by the manufacturer");
public static final Tag TRACK1_DISCRETIONARY_DATA = new TagImpl("9f1f", TagValueType.TEXT, "[Magnetic Stripe] Track 1 Discretionary Data", "Discretionary part of track 1 according to ISO/IEC 7813");
public static final Tag TRACK2_DISCRETIONARY_DATA = new TagImpl("9f20", TagValueType.TEXT, "[Magnetic Stripe] Track 2 Discretionary Data", "Discretionary part of track 2 according to ISO/IEC 7813");
public static final Tag TRANSACTION_TIME = new TagImpl("9f21", TagValueType.NUMERIC, "Transaction Time (HHMMSS)", "Local time that the transaction was authorised");
public static final Tag CA_PUBLIC_KEY_INDEX_TERMINAL = new TagImpl("9f22", TagValueType.BINARY, "Certification Authority Public Key Index - Terminal", "Identifies the certification authoritys public key in conjunction with the RID");
public static final Tag UPPER_CONSEC_OFFLINE_LIMIT = new TagImpl("9f23", TagValueType.BINARY, "Upper Consecutive Offline Limit", "Issuer-specified preference for the maximum number of consecutive offline transactions for this ICC application allowed in a terminal without online capability");
public static final Tag APP_CRYPTOGRAM = new TagImpl("9f26", TagValueType.BINARY, "Application Cryptogram", "Cryptogram returned by the ICC in response of the GENERATE AC command");
public static final Tag CRYPTOGRAM_INFORMATION_DATA = new TagImpl("9f27", TagValueType.BINARY, "Cryptogram Information Data", "Indicates the type of cryptogram and the actions to be performed by the terminal");
public static final Tag ICC_PIN_ENCIPHERMENT_PUBLIC_KEY_CERT = new TagImpl("9f2d", TagValueType.BINARY, "ICC PIN Encipherment Public Key Certificate", "ICC PIN Encipherment Public Key certified by the issuer");
public static final Tag ICC_PIN_ENCIPHERMENT_PUBLIC_KEY_EXP = new TagImpl("9f2e", TagValueType.BINARY, "ICC PIN Encipherment Public Key Exponent", "ICC PIN Encipherment Public Key Exponent used for PIN encipherment");
public static final Tag ICC_PIN_ENCIPHERMENT_PUBLIC_KEY_REM = new TagImpl("9f2f", TagValueType.BINARY, "ICC PIN Encipherment Public Key Remainder", "Remaining digits of the ICC PIN Encipherment Public Key Modulus");
public static final Tag ISSUER_PUBLIC_KEY_EXP = new TagImpl("9f32", TagValueType.BINARY, "Issuer Public Key Exponent", "Issuer public key exponent used for the verification of the Signed Static Application Data and the ICC Public Key Certificate");
public static final Tag TERMINAL_CAPABILITIES = new TagImpl("9f33", TagValueType.BINARY, "Terminal Capabilities", "Indicates the card data input, CVM, and security capabilities of the terminal");
public static final Tag CVM_RESULTS = new TagImpl("9f34", TagValueType.BINARY, "Cardholder Verification (CVM) Results", "Indicates the results of the last CVM performed");
public static final Tag TERMINAL_TYPE = new TagImpl("9f35", TagValueType.NUMERIC, "Terminal Type", "Indicates the environment of the terminal, its communications capability, and its operational control");
public static final Tag APP_TRANSACTION_COUNTER = new TagImpl("9f36", TagValueType.BINARY, "Application Transaction Counter (ATC)", "Counter maintained by the application in the ICC (incrementing the ATC is managed by the ICC)");
public static final Tag UNPREDICTABLE_NUMBER = new TagImpl("9f37", TagValueType.BINARY, "Unpredictable Number", "Value to provide variability and uniqueness to the generation of a cryptogram");
public static final Tag PDOL = new TagImpl("9f38", TagValueType.DOL, "Processing Options Data Object List (PDOL)", "Contains a list of terminal resident data objects (tags and lengths) needed by the ICC in processing the GET PROCESSING OPTIONS command");
public static final Tag POINT_OF_SERVICE_ENTRY_MODE = new TagImpl("9f39", TagValueType.NUMERIC, "Point-of-Service (POS) Entry Mode", "Indicates the method by which the PAN was entered, according to the first two digits of the ISO 8583:1987 POS Entry Mode");
public static final Tag AMOUNT_REFERENCE_CURRENCY = new TagImpl("9f3a", TagValueType.BINARY, "Amount, Reference Currency", "Authorised amount expressed in the reference currency");
public static final Tag APP_REFERENCE_CURRENCY = new TagImpl("9f3b", TagValueType.NUMERIC, "Application Reference Currency", "14 currency codes used between the terminal and the ICC when the Transaction Currency Code is different from the Application Currency Code; each code is 3 digits according to ISO 4217");
public static final Tag TRANSACTION_REFERENCE_CURRENCY_CODE = new TagImpl("9f3c", TagValueType.NUMERIC, "Transaction Reference Currency Code", "Code defining the common currency used by the terminal in case the Transaction Currency Code is different from the Application Currency Code");
public static final Tag TRANSACTION_REFERENCE_CURRENCY_EXP = new TagImpl("9f3d", TagValueType.NUMERIC, "Transaction Reference Currency Exponent", "Indicates the implied position of the decimal point from the right of the transaction amount, with the Transaction Reference Currency Code represented according to ISO 4217");
public static final Tag ADDITIONAL_TERMINAL_CAPABILITIES = new TagImpl("9f40", TagValueType.BINARY, "Additional Terminal Capabilities", "Indicates the data input and output capabilities of the terminal");
public static final Tag TRANSACTION_SEQUENCE_COUNTER = new TagImpl("9f41", TagValueType.NUMERIC, "Transaction Sequence Counter", "Counter maintained by the terminal that is incremented by one for each transaction");
public static final Tag APPLICATION_CURRENCY_CODE = new TagImpl("9f42", TagValueType.NUMERIC, "Application Currency Code", "Indicates the currency in which the account is managed according to ISO 4217");
public static final Tag APP_REFERENCE_CURRECY_EXPONENT = new TagImpl("9f43", TagValueType.NUMERIC, "Application Reference Currency Exponent", "Indicates the implied position of the decimal point from the right of the amount, for each of the 14 reference currencies represented according to ISO 4217");
public static final Tag APP_CURRENCY_EXPONENT = new TagImpl("9f44", TagValueType.NUMERIC, "Application Currency Exponent", "Indicates the implied position of the decimal point from the right of the amount represented according to ISO 4217");
public static final Tag DATA_AUTHENTICATION_CODE = new TagImpl("9f45", TagValueType.BINARY, "Data Authentication Code", "An issuer assigned value that is retained by the terminal during the verification process of the Signed Static Application Data");
public static final Tag ICC_PUBLIC_KEY_CERT = new TagImpl("9f46", TagValueType.BINARY, "ICC Public Key Certificate", "ICC Public Key certified by the issuer");
public static final Tag ICC_PUBLIC_KEY_EXP = new TagImpl("9f47", TagValueType.BINARY, "ICC Public Key Exponent", "ICC Public Key Exponent used for the verification of the Signed Dynamic Application Data");
public static final Tag ICC_PUBLIC_KEY_REMAINDER = new TagImpl("9f48", TagValueType.BINARY, "ICC Public Key Remainder", "Remaining digits of the ICC Public Key Modulus");
public static final Tag DDOL = new TagImpl("9f49", TagValueType.DOL, "Dynamic Data Authentication Data Object List (DDOL)", "List of data objects (tag and length) to be passed to the ICC in the INTERNAL AUTHENTICATE command");
public static final Tag SDA_TAG_LIST = new TagImpl("9f4a", TagValueType.BINARY, "Static Data Authentication Tag List", "List of tags of primitive data objects defined in this specification whose value fields are to be included in the Signed Static or Dynamic Application Data");
public static final Tag SIGNED_DYNAMIC_APPLICATION_DATA = new TagImpl("9f4b", TagValueType.BINARY, "Signed Dynamic Application Data", "Digital signature on critical application parameters for DDA or CDA");
public static final Tag ICC_DYNAMIC_NUMBER = new TagImpl("9f4c", TagValueType.BINARY, "ICC Dynamic Number", "Time-variant number generated by the ICC, to be captured by the terminal");
public static final Tag LOG_ENTRY = new TagImpl("9f4d", TagValueType.BINARY, "Log Entry", "Provides the SFI of the Transaction Log file and its number of records");
public static final Tag MERCHANT_NAME_AND_LOCATION = new TagImpl("9f4e", TagValueType.TEXT, "Merchant Name and Location", "Indicates the name and location of the merchant");
public static final Tag LOG_FORMAT = new TagImpl("9f4f", TagValueType.DOL, "Log Format", "List (in tag and length format) of data objects representing the logged data elements that are passed to the terminal when a transaction log record is read");
public static final Tag FCI_ISSUER_DISCRETIONARY_DATA = new TagImpl("bf0c", TagValueType.BINARY, "File Control Information (FCI) Issuer Discretionary Data", "Issuer discretionary part of the FCI (e.g. O/S Manufacturer proprietary data)");
public static final Tag TRACK1_DATA = new TagImpl("56", TagValueType.BINARY, "Track 1 Data", "Track 1 Data contains the data objects of the track 1 according to [ISO/IEC 7813] Structure B, excluding start sentinel, end sentinel and LRC.");
public static final Tag TERMINAL_TRANSACTION_QUALIFIERS = new TagImpl("9f66", TagValueType.BINARY, "Terminal Transaction Qualifiers", "Provided by the reader in the GPO command and used by the card to determine processing choices based on reader functionality");
public static final Tag TRACK2_DATA = new TagImpl("9f6b", TagValueType.BINARY, "Track 2 Data", "Track 2 Data contains the data objects of the track 2 according to [ISO/IEC 7813] Structure B, excluding start sentinel, end sentinel and LRC.");
public static final Tag VLP_ISSUER_AUTHORISATION_CODE = new TagImpl("9f6e", TagValueType.BINARY, "Visa Low-Value Payment (VLP) Issuer Authorisation Code", "");
public static final Tag EXTENDED_SELECTION = new TagImpl("9f29", TagValueType.BINARY, "Indicates the card's preference for the kernel on which the contactless application can be processed", "");
public static final Tag KERNEL_IDENTIFIER = new TagImpl("9f2a", TagValueType.BINARY, "The value to be appended to the ADF Name in the data field of the SELECT command, if the Extended Selection Support flag is present and set to 1", "");
public static Tag getNotNull(byte[] tagBytes) {
Tag tag = find(tagBytes);
if (tag == null) {
tag = createUnknownTag(tagBytes);
}
return tag;
}
public static Tag createUnknownTag(byte[] tagBytes) {
return new TagImpl(tagBytes, TagValueType.BINARY, "[UNKNOWN TAG]", "");
}
public static Tag find(byte[] tagBytes) {
return (Tag) tags.get(ByteArrayWrapper.wrapperAround(tagBytes));
}
private static void addTag(Tag tag) {
ByteArrayWrapper baw = ByteArrayWrapper.wrapperAround(tag.getTagBytes());
if (tags.containsKey(baw)) {
throw new IllegalArgumentException("Tag already added " + tag);
}
tags.put(baw, tag);
}
static {
Field[] fields = EMVTags.class.getFields();
for (Field f : fields) {
if (f.getType() == Tag.class) {
try {
Tag t = (Tag) f.get(null);
addTag(t);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
}
addPaymentSystemTag(Util.fromHexString("A000000315"), new TagImpl("c1", TagValueType.BINARY, "?", "Example: BER-TLV[c1, 02 (raw 02), 1101]"));
}
private static void addIssuerTag(IssuerIdentificationNumber iin, Tag tag) {
ByteArrayWrapper tagBytesWrapped = ByteArrayWrapper.wrapperAround(tag.getTagBytes());
LinkedHashMap<ByteArrayWrapper, Tag> issuerTags = (LinkedHashMap) issuerToTagsMap.get(iin);
if (issuerTags == null) {
issuerTags = new LinkedHashMap<ByteArrayWrapper, Tag>();
issuerToTagsMap.put(iin, issuerTags);
}
if (issuerTags.containsKey(tagBytesWrapped)) {
throw new IllegalArgumentException("Tag already added " + tag);
}
issuerTags.put(tagBytesWrapped, tag);
}
private static void addPaymentSystemTag(byte[] ridBytes, Tag tag) {
ByteArrayWrapper tagBytesWrapped = ByteArrayWrapper.wrapperAround(tag.getTagBytes());
ByteArrayWrapper ridBytesWrapped = ByteArrayWrapper.wrapperAround(ridBytes);
LinkedHashMap<ByteArrayWrapper, Tag> paymentSystemTags = (LinkedHashMap) paymentSystemToTagsMap.get(ridBytesWrapped);
if (paymentSystemTags == null) {
paymentSystemTags = new LinkedHashMap<ByteArrayWrapper, Tag>();
paymentSystemToTagsMap.put(ridBytesWrapped, paymentSystemTags);
}
if (paymentSystemTags.containsKey(tagBytesWrapped)) {
throw new IllegalArgumentException("Tag already added " + tag);
}
paymentSystemTags.put(tagBytesWrapped, tag);
}
public static void main(String[] args) {
System.out.println(find(new byte[]{66}));
System.out.println(find(new byte[]{95, 32}));
System.out.println(getNotNull(new byte[]{95, 33}));
}
public static Iterator iterator() {
return tags.values().iterator();
}
private EMVTags() {
throw new UnsupportedOperationException("Not allowed to instantiate");
}
}

View File

@ -0,0 +1,59 @@
package sasc.emv;
import java.util.Arrays;
import sasc.util.Util;
public class IssuerIdentificationNumber {
byte[] iinBytes;
public IssuerIdentificationNumber(byte[] iinBytes) {
if (iinBytes == null) {
throw new NullPointerException("Param iinBytes cannot be null");
}
if (iinBytes.length != 3) {
throw new IllegalArgumentException("Param iinBytes must have length 3, but was " + iinBytes.length);
}
this.iinBytes = Arrays.copyOf(iinBytes, iinBytes.length);
}
public IssuerIdentificationNumber(int iin) {
if (iin < 0 || iin > 1000000) {
throw new IllegalArgumentException("IIN must be between 0 and 999999, but was " + iin);
}
byte[] tmp = Util.intToBinaryEncodedDecimalByteArray(iin);
if (tmp.length != 6) {
this.iinBytes = Util.resizeArray(tmp, 6);
} else {
this.iinBytes = tmp;
}
}
public int getValue() {
return Util.binaryHexCodedDecimalToInt(this.iinBytes);
}
public byte[] getBytes() {
return Arrays.copyOf(this.iinBytes, this.iinBytes.length);
}
public boolean equals(Object obj) {
if (!(obj instanceof IssuerIdentificationNumber)) {
return false;
}
IssuerIdentificationNumber that = (IssuerIdentificationNumber) obj;
if (this == that) {
return true;
}
if (Arrays.equals(getBytes(), that.getBytes())) {
return true;
}
return false;
}
public int hashCode() {
int hash = 7;
return 97 * hash + Arrays.hashCode(this.iinBytes);
}
}

View File

@ -0,0 +1,125 @@
package sasc.iso7816;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import sasc.util.Util;
public class BERTLV
{
private Tag tag;
private byte[] rawEncodedLengthBytes;
private byte[] valueBytes;
private int length;
public BERTLV(Tag tag, int length, byte[] rawEncodedLengthBytes, byte[] valueBytes) {
if (length != valueBytes.length)
{
throw new IllegalArgumentException("length != bytes.length");
}
this.tag = tag;
this.rawEncodedLengthBytes = rawEncodedLengthBytes;
this.valueBytes = valueBytes;
this.length = length;
}
public BERTLV(Tag tag, byte[] valueBytes) {
this.tag = tag;
this.rawEncodedLengthBytes = encodeLength(valueBytes.length);
this.valueBytes = valueBytes;
this.length = valueBytes.length;
}
public static byte[] encodeLength(int length) {
if (length <= 127)
return new byte[] { (byte)length };
if (length <= 255) {
return new byte[] { -127, (byte)length };
}
if (length <= 65535) {
return new byte[] { -126, (byte)(length >> 8), (byte)length };
}
if (length <= 16777215) {
return new byte[] { -125, (byte)(length >> 16), (byte)(length >> 8), (byte)length };
}
throw new IllegalArgumentException("SEQUENCE too long");
}
public byte[] getTagBytes() { return this.tag.getTagBytes(); }
public byte[] getRawEncodedLengthBytes() { return this.rawEncodedLengthBytes; }
public byte[] getValueBytes() { return this.valueBytes; }
public ByteArrayInputStream getValueStream() { return new ByteArrayInputStream(this.valueBytes); }
public byte[] toBERTLVByteArray() {
byte[] tagBytes = this.tag.getTagBytes();
ByteArrayOutputStream stream = new ByteArrayOutputStream(tagBytes.length + this.rawEncodedLengthBytes.length + this.valueBytes.length);
stream.write(tagBytes, 0, tagBytes.length);
stream.write(this.rawEncodedLengthBytes, 0, this.rawEncodedLengthBytes.length);
stream.write(this.valueBytes, 0, this.valueBytes.length);
return stream.toByteArray();
}
public String toString() { return "BER-TLV[" + Util.byteArrayToHexString(getTagBytes()) + ", " + Util.int2Hex(this.length) + " (raw " + Util.byteArrayToHexString(this.rawEncodedLengthBytes) + "), " + Util.byteArrayToHexString(this.valueBytes) + "]"; }
public Tag getTag() { return this.tag; }
public int getLength() { return this.length; }
public static void main(String[] args) throws Exception {}
}

View File

@ -0,0 +1,33 @@
package sasc.iso7816;
public class SmartCardException
extends RuntimeException
{
public SmartCardException(String message) { super(message); }
public SmartCardException(String message, Throwable cause) { super(message, cause); }
public SmartCardException(Throwable cause) { super(cause); }
}

View File

@ -0,0 +1,33 @@
package sasc.iso7816;
public class TLVException
extends SmartCardException
{
public TLVException(String message) { super(message); }
public TLVException(String message, Throwable cause) { super(message, cause); }
public TLVException(Throwable cause) { super(cause); }
}

View File

@ -0,0 +1,275 @@
package sasc.iso7816;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import sasc.emv.EMVTags;
import sasc.util.Util;
public class TLVUtil
{
private static Tag searchTagById(byte[] tagIdBytes) { return EMVTags.getNotNull(tagIdBytes); }
private static Tag searchTagById(ByteArrayInputStream stream) { return searchTagById(readTagIdBytes(stream)); }
public static String getFormattedTagAndLength(byte[] data, int indentLength) {
StringBuilder buf = new StringBuilder();
String indent = Util.getSpaces(indentLength);
ByteArrayInputStream stream = new ByteArrayInputStream(data);
boolean firstLine = true;
while (stream.available() > 0) {
if (firstLine) {
firstLine = false;
} else {
buf.append("\n");
}
buf.append(indent);
Tag tag = searchTagById(stream);
int length = readTagLength(stream);
buf.append(Util.prettyPrintHex(tag.getTagBytes()));
buf.append(" ");
buf.append(Util.byteArrayToHexString(Util.intToByteArray(length)));
buf.append(" -- ");
buf.append(tag.getName());
}
return buf.toString();
}
public static byte[] readTagIdBytes(ByteArrayInputStream stream) {
ByteArrayOutputStream tagBAOS = new ByteArrayOutputStream();
byte tagFirstOctet = (byte)stream.read();
tagBAOS.write(tagFirstOctet);
byte MASK = 31;
if ((tagFirstOctet & MASK) == MASK) {
byte tlvIdNextOctet;
do {
int nextOctet = stream.read();
if (nextOctet < 0) {
break;
}
tlvIdNextOctet = (byte)nextOctet;
tagBAOS.write(tlvIdNextOctet);
}
while (Util.isBitSet(tlvIdNextOctet, 8) && (!Util.isBitSet(tlvIdNextOctet, 8) || (tlvIdNextOctet & 0x7F) != 0));
}
return tagBAOS.toByteArray();
}
public static int readTagLength(ByteArrayInputStream stream) {
int length, tmpLength = stream.read();
if (tmpLength < 0) {
throw new TLVException("Negative length: " + tmpLength);
}
if (tmpLength <= 127) {
length = tmpLength;
} else if (tmpLength == 128) {
length = tmpLength;
} else {
int numberOfLengthOctets = tmpLength & 0x7F;
tmpLength = 0;
for (int i = 0; i < numberOfLengthOctets; i++) {
int nextLengthOctet = stream.read();
if (nextLengthOctet < 0) {
throw new TLVException("EOS when reading length bytes");
}
tmpLength <<= 8;
tmpLength |= nextLengthOctet;
}
length = tmpLength;
}
return length;
}
public static BERTLV getNextTLV(ByteArrayInputStream stream) {
byte[] valueBytes;
if (stream.available() < 2) {
throw new TLVException("Error parsing data. Available bytes < 2 . Length=" + stream.available());
}
stream.mark(0);
int peekInt = stream.read();
byte peekByte = (byte)peekInt;
while (peekInt != -1 && (peekByte == -1 || peekByte == 0)) {
stream.mark(0);
peekInt = stream.read();
peekByte = (byte)peekInt;
}
stream.reset();
if (stream.available() < 2) {
throw new TLVException("Error parsing data. Available bytes < 2 . Length=" + stream.available());
}
byte[] tagIdBytes = readTagIdBytes(stream);
stream.mark(0);
int posBefore = stream.available();
int length = readTagLength(stream);
int posAfter = stream.available();
stream.reset();
byte[] lengthBytes = new byte[posBefore - posAfter];
if (lengthBytes.length < 1 || lengthBytes.length > 4) {
throw new TLVException("Number of length bytes must be from 1 to 4. Found " + lengthBytes.length);
}
stream.read(lengthBytes, 0, lengthBytes.length);
int rawLength = Util.byteArrayToInt(lengthBytes);
Tag tag = searchTagById(tagIdBytes);
if (rawLength == 128) {
stream.mark(0);
int prevOctet = 1;
int len = 0;
while (true) {
len++;
int curOctet = stream.read();
if (curOctet < 0) {
throw new TLVException("Error parsing data. TLV length byte indicated indefinite length, but EOS was reached before 0x0000 was found" + stream
.available());
}
if (prevOctet == 0 && curOctet == 0) {
break;
}
prevOctet = curOctet;
}
len -= 2;
valueBytes = new byte[len];
stream.reset();
stream.read(valueBytes, 0, len);
length = len;
} else {
if (stream.available() < length) {
throw new TLVException("Length byte(s) indicated " + length + " value bytes, but only " + stream.available() + " " + ((stream.available() > 1) ? "are" : "is") + " available");
}
valueBytes = new byte[length];
stream.read(valueBytes, 0, length);
}
stream.mark(0);
peekInt = stream.read();
peekByte = (byte)peekInt;
while (peekInt != -1 && (peekByte == -1 || peekByte == 0)) {
stream.mark(0);
peekInt = stream.read();
peekByte = (byte)peekInt;
}
stream.reset();
return new BERTLV(tag, length, lengthBytes, valueBytes);
}
private static String getTagValueAsString(Tag tag, byte[] value) {
StringBuilder buf = new StringBuilder();
switch (tag.getTagValueType()) {
case TEXT:
buf.append("=");
buf.append(new String(value));
break;
case NUMERIC:
buf.append("NUMERIC");
break;
case BINARY:
buf.append("BINARY");
break;
case MIXED:
buf.append("=");
buf.append(Util.getSafePrintChars(value));
break;
case DOL:
buf.append("");
break;
}
return buf.toString();
}
public static List<TagAndLength> parseTagAndLength(byte[] data) {
ByteArrayInputStream stream = new ByteArrayInputStream(data);
List<TagAndLength> tagAndLengthList = new ArrayList<TagAndLength>();
while (stream.available() > 0) {
if (stream.available() < 2) {
throw new SmartCardException("Data length < 2 : " + stream.available());
}
byte[] tagIdBytes = readTagIdBytes(stream);
int tagValueLength = readTagLength(stream);
Tag tag = searchTagById(tagIdBytes);
tagAndLengthList.add(new TagAndLength(tag, tagValueLength));
}
return tagAndLengthList;
}
}

View File

@ -0,0 +1,27 @@
package sasc.iso7816;
public interface Tag
{
boolean isConstructed();
byte[] getTagBytes();
String getName();
String getDescription();
TagType getType();
TagValueType getTagValueType();
Class getTagClass();
int getNumTagBytes();
public enum Class
{
UNIVERSAL, APPLICATION, CONTEXT_SPECIFIC, PRIVATE;
}
}

View File

@ -0,0 +1,51 @@
package sasc.iso7816;
import java.util.Arrays;
public class TagAndLength
{
private Tag tag;
private int length;
public TagAndLength(Tag tag, int length) {
this.tag = tag;
this.length = length;
}
public Tag getTag() { return this.tag; }
public int getLength() { return this.length; }
public byte[] getBytes() {
byte[] tagBytes = this.tag.getTagBytes();
byte[] tagAndLengthBytes = Arrays.copyOf(tagBytes, tagBytes.length + 1);
tagAndLengthBytes[tagAndLengthBytes.length - 1] = (byte)this.length;
return tagAndLengthBytes;
}
public String toString() { return this.tag.toString() + " length: " + this.length; }
}

View File

@ -0,0 +1,141 @@
package sasc.iso7816;
import java.util.Arrays;
import sasc.util.Util;
public class TagImpl
implements Tag {
byte[] idBytes;
String name;
String description;
TagValueType tagValueType;
Tag.Class tagClass;
TagType type;
public TagImpl(int idDecimal, TagValueType tagValueType) {
String octal = Integer.toOctalString(idDecimal);
if (octal.length() == 1) {
octal = "0" + octal;
} else if (octal.length() == 3) {
octal = "8" + octal;
}
build(Util.fromHexString(octal), tagValueType, null, null);
}
public TagImpl(String id, TagValueType tagValueType, String name, String description) {
build(Util.fromHexString(id), tagValueType, name, description);
}
public TagImpl(byte[] idBytes, TagValueType tagValueType, String name, String description) {
build(idBytes, tagValueType, name, description);
}
private void build(byte[] idBytes, TagValueType tagValueType, String name, String description) {
if (idBytes == null) {
throw new IllegalArgumentException("Param id cannot be null");
}
if (idBytes.length == 0) {
throw new IllegalArgumentException("Param id cannot be empty");
}
if (tagValueType == null) {
throw new IllegalArgumentException("Param tagValueType cannot be null");
}
this.idBytes = idBytes;
this.name = (name != null) ? name : "";
this.description = (description != null) ? description : "";
this.tagValueType = tagValueType;
if (Util.isBitSet(this.idBytes[0], 6)) {
this.type = TagType.CONSTRUCTED;
} else {
this.type = TagType.PRIMITIVE;
}
byte classValue = (byte) (this.idBytes[0] >>> 6 & 0x3);
switch (classValue) {
case 0:
this.tagClass = Tag.Class.UNIVERSAL;
return;
case 1:
this.tagClass = Tag.Class.APPLICATION;
return;
case 2:
this.tagClass = Tag.Class.CONTEXT_SPECIFIC;
return;
case 3:
this.tagClass = Tag.Class.PRIVATE;
return;
}
throw new RuntimeException("UNEXPECTED TAG CLASS: " + Util.byte2BinaryLiteral(classValue) + " " + Util.byteArrayToHexString(this.idBytes) + " " + name);
}
public boolean isConstructed() {
return (this.type == TagType.CONSTRUCTED);
}
public byte[] getTagBytes() {
return this.idBytes;
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public TagValueType getTagValueType() {
return this.tagValueType;
}
public TagType getType() {
return this.type;
}
public Tag.Class getTagClass() {
return this.tagClass;
}
public boolean equals(Object other) {
if (!(other instanceof Tag)) {
return false;
}
Tag that = (Tag) other;
if (getTagBytes().length != that.getTagBytes().length) {
return false;
}
return Arrays.equals(getTagBytes(), that.getTagBytes());
}
public int hashCode() {
int hash = 3;
return 59 * hash + Arrays.hashCode(this.idBytes);
}
public int getNumTagBytes() {
return this.idBytes.length;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Tag[");
sb.append(Util.byteArrayToHexString(getTagBytes()));
sb.append("] Name=");
sb.append(getName());
sb.append(", TagType=");
sb.append(getType());
sb.append(", ValueType=");
sb.append(getTagValueType());
sb.append(", Class=");
sb.append(this.tagClass);
return sb.toString();
}
public static void main(String[] args) throws Exception {
TagImpl tag = new TagImpl("bf0c", TagValueType.BINARY, "", "");
System.out.println(tag);
}
}

View File

@ -0,0 +1,6 @@
package sasc.iso7816;
public enum TagType {
PRIMITIVE,
CONSTRUCTED;
}

View File

@ -0,0 +1,5 @@
package sasc.iso7816;
public enum TagValueType {
BINARY, NUMERIC, TEXT, MIXED, DOL, TEMPLATE;
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2010 sasc
*
* 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 sasc.util;
import java.util.Arrays;
public final class ByteArrayWrapper {
private final byte[] data;
private final int hashcode;
private ByteArrayWrapper(byte[] data) {
this.data = data;
this.hashcode = Arrays.hashCode(data);
}
public static ByteArrayWrapper wrapperAround(byte[] data) {
if (data == null) {
throw new NullPointerException();
}
return new ByteArrayWrapper(data);
}
public static ByteArrayWrapper copyOf(byte[] data) {
if (data == null) {
throw new NullPointerException();
}
return new ByteArrayWrapper(Util.copyByteArray(data));
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ByteArrayWrapper)) {
return false;
}
return Arrays.equals(data, ((ByteArrayWrapper) other).data);
}
@Override
public int hashCode() {
return hashcode;
}
}

View File

@ -0,0 +1,689 @@
/*
* Copyright 2010 sasc
*
* 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 sasc.util;
import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.BitSet;
import java.util.Date;
import java.util.StringTokenizer;
/**
*
* @author sasc
*/
public class Util {
private Util() {
throw new UnsupportedOperationException("Not allowed to instantiate");
}
public static String getSpaces(int length) {
StringBuilder buf = new StringBuilder(length);
for (int i = 0; i < length; i++) {
buf.append(" ");
}
return buf.toString();
}
public static String prettyPrintHex(String in, int indent, boolean wrapLines) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < in.length(); i++) {
char c = in.charAt(i);
buf.append(c);
int nextPos = i+1;
if (wrapLines && nextPos % 32 == 0 && nextPos != in.length()) {
buf.append("\n").append(getSpaces(indent));
} else if (nextPos % 2 == 0 && nextPos != in.length()) {
buf.append(" ");
}
}
return buf.toString();
}
public static String prettyPrintHex(String in, int indent){
return prettyPrintHex(in, indent, true);
}
public static String prettyPrintHex(byte[] data, int indent) {
return Util.prettyPrintHex(Util.byteArrayToHexString(data), indent, true);
}
public static String prettyPrintHex(byte[] data) {
return Util.prettyPrintHex(Util.byteArrayToHexString(data), 0, true);
}
public static String prettyPrintHex(byte[] data, int startPos, int length) {
return Util.prettyPrintHex(Util.byteArrayToHexString(data, startPos, length), 0, true);
}
public static String prettyPrintHexNoWrap(byte[] data) {
return Util.prettyPrintHex(Util.byteArrayToHexString(data), 0, false);
}
public static String prettyPrintHexNoWrap(byte[] data, int startPos, int length) {
return Util.prettyPrintHex(Util.byteArrayToHexString(data, startPos, length), 0, false);
}
public static String prettyPrintHexNoWrap(String in) {
return Util.prettyPrintHex(in, 0, false);
}
public static String prettyPrintHex(String in) {
return prettyPrintHex(in, 0, true);
}
public static String prettyPrintHex(BigInteger bi) {
byte[] data = bi.toByteArray();
if (data[0] == (byte) 0x00) {
byte[] tmp = new byte[data.length - 1];
System.arraycopy(data, 1, tmp, 0, data.length - 1);
data = tmp;
}
return prettyPrintHex(data);
}
public static byte[] performRSA(byte[] dataBytes, byte[] expBytes, byte[] modBytes) {
int inBytesLength = dataBytes.length;
if (expBytes[0] >= (byte) 0x80) {
//Prepend 0x00 to modulus
byte[] tmp = new byte[expBytes.length + 1];
tmp[0] = (byte) 0x00;
System.arraycopy(expBytes, 0, tmp, 1, expBytes.length);
expBytes = tmp;
}
if (modBytes[0] >= (byte) 0x80) {
//Prepend 0x00 to modulus
byte[] tmp = new byte[modBytes.length + 1];
tmp[0] = (byte) 0x00;
System.arraycopy(modBytes, 0, tmp, 1, modBytes.length);
modBytes = tmp;
}
if (dataBytes[0] >= (byte) 0x80) {
//Prepend 0x00 to signed data to avoid that the most significant bit is interpreted as the "signed" bit
byte[] tmp = new byte[dataBytes.length + 1];
tmp[0] = (byte) 0x00;
System.arraycopy(dataBytes, 0, tmp, 1, dataBytes.length);
dataBytes = tmp;
}
BigInteger exp = new BigInteger(expBytes);
BigInteger mod = new BigInteger(modBytes);
BigInteger data = new BigInteger(dataBytes);
byte[] result = data.modPow(exp, mod).toByteArray();
if (result.length == (inBytesLength+1) && result[0] == (byte)0x00) {
//Remove 0x00 from beginning of array
byte[] tmp = new byte[inBytesLength];
System.arraycopy(result, 1, tmp, 0, inBytesLength);
result = tmp;
}
return result;
}
public static byte[] calculateSHA1(byte[] data) throws NoSuchAlgorithmException {
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
return sha1.digest(data);
}
public static String byte2Hex(byte b) {
String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
int nb = b & 0xFF;
int i_1 = (nb >>> 4) & 0xF;
int i_2 = nb & 0xF;
return HEX_DIGITS[i_1] + HEX_DIGITS[i_2];
}
public static String short2Hex(short s) {
byte b1 = (byte) (s >>> 8);
byte b2 = (byte) (s & 0xFF);
return byte2Hex(b1) + byte2Hex(b2);
}
public static int byteToInt(byte b) {
return (int) b & 0xFF;
}
public static int byteToInt(byte first, byte second) {
int value = (first & 0xFF) << 8;
value += second & 0xFF;
return value;
}
public static short byte2Short(byte b1, byte b2) {
return (short) ((b1 << 8) | (b2 & 0xFF));
}
public static String getFormattedNanoTime(long nano) {
StringBuilder buf = new StringBuilder();
buf.append((int) (nano / 1000000));
buf.append("ms ");
buf.append(nano % 1000000);
buf.append("ns");
return buf.toString();
}
public static byte[] getCurrentDateAsNumericEncodedByteArray(){
SimpleDateFormat format = new SimpleDateFormat("yyMMdd");
return fromHexString(format.format(new Date()));
}
//This prints all non-control characters common to all parts of ISO/IEC 8859
//See EMV book 4 Annex B: Table 36: Common Character Set
public static String getSafePrintChars(byte[] byteArray) {
if (byteArray == null) {
return "";
}
return getSafePrintChars(byteArray, 0, byteArray.length);
}
public static String getSafePrintChars(byte[] byteArray, int startPos, int length) {
if (byteArray == null) {
return "";
}
if(byteArray.length < startPos+length){
throw new IllegalArgumentException("startPos("+startPos+")+length("+length+") > byteArray.length("+byteArray.length+")");
}
StringBuilder buf = new StringBuilder();
for (int i = startPos; i < startPos+length; i++) {
if (byteArray[i] >= (byte) 0x20 && byteArray[i] < (byte) 0x7F) {
buf.append((char) byteArray[i]);
} else {
buf.append(".");
}
}
return buf.toString();
}
/**
* Converts a byte array into a hex string.
* @param byteArray the byte array source
* @return a hex string representing the byte array
*/
public static String byteArrayToHexString(final byte[] byteArray) {
if (byteArray == null) {
return "";
}
return byteArrayToHexString(byteArray, 0, byteArray.length);
}
public static String byteArrayToHexString(final byte[] byteArray, int startPos, int length) {
if (byteArray == null) {
return "";
}
if(byteArray.length < startPos+length){
throw new IllegalArgumentException("startPos("+startPos+")+length("+length+") > byteArray.length("+byteArray.length+")");
}
StringBuilder hexData = new StringBuilder();
int onebyte;
for (int i = 0; i < length; i++) {
onebyte = ((0x000000ff & byteArray[startPos+i]) | 0xffffff00);
hexData.append(Integer.toHexString(onebyte).substring(6));
}
return hexData.toString();
}
public static String int2Hex(int i) {
String hex = Integer.toHexString(i);
if (hex.length() % 2 != 0) {
hex = "0" + hex;
}
return hex;
}
public static String int2HexZeroPad(int i) {
String hex = int2Hex(i);
if (hex.length() % 2 != 0) {
hex = "0" + hex;
}
return hex;
}
/**
* The length of the returned array depends on the size of the int
* @param value
* @return
*/
public static byte[] intToByteArray(int value) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte one = (byte) (value >>> 24);
byte two = (byte) (value >>> 16);
byte three = (byte) (value >>> 8);
byte four = (byte) (value);
boolean found = false;
if (one > 0x00) {
baos.write(one);
found = true;
}
if (found || two > 0x00) {
baos.write(two);
found = true;
}
if (found || three > 0x00) {
baos.write(three);
}
baos.write(four);
return baos.toByteArray();
}
/**
* Returns a byte array with length = 4
* @param value
* @return
*/
public static byte[] intToByteArray4(int value) {
return new byte[]{
(byte) (value >>> 24),
(byte) (value >>> 16),
(byte) (value >>> 8),
(byte) value};
}
public static int byteArrayToInt(byte[] byteArray) {
return byteArrayToInt(byteArray, 0, byteArray.length);
}
public static int byteArrayToInt(byte[] byteArray, int startPos, int length) {
if (byteArray == null) {
throw new IllegalArgumentException("Parameter 'byteArray' cannot be null");
}
if (length <= 0 || length > 4) {
throw new IllegalArgumentException("Length must be between 1 and 4. Length = " + length);
}
if (length == 4 && Util.isBitSet(byteArray[startPos], 8)){
throw new IllegalArgumentException("Signed bit is set (leftmost bit): " + Util.byte2Hex(byteArray[startPos]));
}
int value = 0;
for (int i = 0; i < length; i++) {
value += ((byteArray[startPos+i] & 0xFF) << 8 * (length - i - 1));
}
return value;
}
public static long byteArrayToLong(byte[] byteArray, int startPos, int length) {
if (byteArray == null) {
throw new IllegalArgumentException("Parameter 'byteArray' cannot be null");
}
if (length <= 0 || length > 8) {
throw new IllegalArgumentException("Length must be between 1 and 4. Length = " + length);
}
if (length == 8 && Util.isBitSet(byteArray[startPos], 8)){
throw new IllegalArgumentException("Signed bit is set (leftmost bit): " + Util.byte2Hex(byteArray[startPos]));
}
long value = 0;
for (int i = 0; i < length; i++) {
value += ((byteArray[startPos+i] & (long)0xFF) << 8 * (length - i - 1));
}
return value;
}
public static byte[] fromHexString(String encoded) {
encoded = removeSpaces(encoded);
if (encoded.length() == 0){
return new byte[0];
}
if ((encoded.length() % 2) != 0) {
throw new IllegalArgumentException("Input string must contain an even number of characters: "+encoded);
}
final byte result[] = new byte[encoded.length() / 2];
final char enc[] = encoded.toCharArray();
for (int i = 0; i < enc.length; i += 2) {
StringBuilder curr = new StringBuilder(2);
curr.append(enc[i]).append(enc[i + 1]);
result[i / 2] = (byte) Integer.parseInt(curr.toString(), 16);
}
return result;
}
public static String removeCRLFTab(String s) {
StringTokenizer st = new StringTokenizer(s, "\r\n\t", false);
StringBuilder buf = new StringBuilder();
while (st.hasMoreElements()) {
buf.append(st.nextElement());
}
return buf.toString();
}
public static String removeSpaces(String s) {
return s.replaceAll(" ", "");
}
/**
* Binary Coded Decimal (BCD)
* @param val
* @return
*/
public static byte[] intToBinaryEncodedDecimalByteArray(int val){
String str = String.valueOf(val);
if(str.length() % 2 != 0){
str = "0"+str;
}
return Util.fromHexString(str);
}
/**
* This method converts the literal hex representation of a byte to an int.
* eg 0x70 = 70 (int)
* @param b
*/
public static int binaryCodedDecimalToInt(byte b) {
String hex = Util.byte2Hex(b);
try {
return Integer.parseInt(hex);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("The hex representation of argument b must be digits only, and integer", ex);
}
}
/**
* This method converts the literal hex representation of a decimal
* encoded in 1-5 bytes to an int.
* The value should not be larger than Integer.MAX_VALUE
*
* eg 0x70 = 70 (decimal)
* eg 0x21 47 48 36 47 = 2147483647 (decimal)
* @param hex
*/
public static int binaryHexCodedDecimalToInt(String hex) {
if (hex == null) {
throw new IllegalArgumentException("Param hex cannot be null");
}
hex = Util.removeSpaces(hex);
if (hex.length() > 10) {
throw new IllegalArgumentException("There must be a maximum of 5 hex octets. hex=" + hex);
}
try {
return Integer.parseInt(hex);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("Argument hex must be all digits. hex="+hex, ex);
}
}
/**
* This method converts a 1-5 byte BCD to an int.
* eg 0x7099 = 7099 (int)
* @param bcdArray
*/
public static int binaryHexCodedDecimalToInt(byte[] bcdArray) {
if (bcdArray == null) {
throw new IllegalArgumentException("Param bcdArray cannot be null");
}
return binaryHexCodedDecimalToInt(Util.byteArrayToHexString(bcdArray));
}
/**
* This returns a String with length = 8
* @param val
* @return
*/
public static String byte2BinaryLiteral(byte val) {
String s = Integer.toBinaryString(Util.byteToInt(val));
if (s.length() < 8) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8 - s.length(); i++) {
sb.append('0');
}
sb.append(s);
s = sb.toString();
}
return s;
}
/**
* Returns a bitset containing the values in bytes.
* The byte-ordering of bytes must be big-endian which means the most significant bit is in element 0.
*
* @param bytes
* @return
*/
public static BitSet byteArray2BitSet(byte[] bytes) {
BitSet bits = new BitSet();
for (int i = 0; i < bytes.length * 8; i++) {
if ((bytes[bytes.length - i / 8 - 1] & (1 << (i % 8))) > 0) {
bits.set(i);
}
}
return bits;
}
/* Returns a byte array of at least length 1.
* The most significant bit in the result is guaranteed not to be a 1
* (since BitSet does not support sign extension).
* The byte-ordering of the result is big-endian which means the most significant bit is in element 0.
* The bit at index 0 of the bit set is assumed to be the least significant bit.
*/
public static byte[] bitSet2ByteArray(BitSet bits) {
byte[] bytes = new byte[bits.length() / 8 + 1];
for (int i = 0; i < bits.length(); i++) {
if (bits.get(i)) {
bytes[bytes.length - i / 8 - 1] |= 1 << (i % 8);
}
}
return bytes;
}
/**
*
* @param val
* @param bitPos The leftmost bit is 8 (the most significant bit)
* @return
*/
public static boolean isBitSet(byte val, int bitPos) {
if (bitPos < 1 || bitPos > 8) {
throw new IllegalArgumentException("parameter 'bitPos' must be between 1 and 8. bitPos=" + bitPos);
}
if ((val >>> (bitPos - 1) & 0x1) == 1) {
return true;
}
return false;
}
// /**
// *
// * @param val
// * @return
// */
// public static int getBitsSetCount(byte val) {
// int numBitsSet = 0;
// for(int i=1; i<=8; i++){
// if(Util.isBitSet(val, i)){
// numBitsSet++;
// }
// }
// return numBitsSet;
// }
/**
*
* @param data
* @param bitPos The leftmost bit is 8
* @param on
* @return
*/
public static byte setBit(byte data, int bitPos, boolean on) {
if (bitPos < 1 || bitPos > 8) {
throw new IllegalArgumentException("parameter 'bitPos' must be between 1 and 8. bitPos=" + bitPos);
}
if (on) { //Set bit
return data |= 1 << (bitPos - 1);
} else { //Unset bit
return data &= ~(1 << (bitPos - 1));
}
}
public static byte[] generateRandomBytes(int numBytes){
//TODO get bytes from a hardware RNG, or set seed
byte[] rndBytes = new byte[numBytes];
SecureRandom random = new SecureRandom();
random.nextBytes(rndBytes);
return rndBytes;
}
public static InputStream loadResource(Class cls, String path){
return cls.getResourceAsStream(path);
}
/**
* Copies the specified array, prepending 0x00, or cutting off MSBytes if necessary
* @param original
* @param newLength
* @return
*/
public static byte[] resizeArray(byte[] original, int newLength) {
if(original == null){
throw new IllegalArgumentException("byte array cannot be null");
}
if(newLength < 0){
throw new IllegalArgumentException("Illegal new length: "+newLength+". Must be >= 0");
}
if(newLength == 0){
return new byte[0];
}
byte[] tmp = new byte[newLength];
int srcPos = tmp.length > original.length ? 0 : original.length - tmp.length;
int destPos = tmp.length > original.length ? tmp.length - original.length : 0;
int length = tmp.length > original.length ? original.length : tmp.length;
System.arraycopy(original, srcPos, tmp, destPos, length);
return tmp;
}
public static byte[] copyByteArray(byte[] array2Copy){
if (array2Copy == null) {
//return new byte[0] instead?
throw new IllegalArgumentException("Argument 'array2Copy' cannot be null");
}
return copyByteArray(array2Copy, 0, array2Copy.length);
}
public static byte[] copyByteArray(byte[] array2Copy, int startPos, int length){
if (array2Copy == null) {
//return new byte[0] instead?
throw new IllegalArgumentException("Argument 'array2Copy' cannot be null");
}
if(array2Copy.length < startPos+length){
throw new IllegalArgumentException("startPos("+startPos+")+length("+length+") > byteArray.length("+array2Copy.length+")");
}
byte[] copy = new byte[array2Copy.length];
System.arraycopy(array2Copy, startPos, copy, 0, length);
return copy;
}
public static String getStackTrace(Throwable t){
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
public static String readInputStreamToString(InputStream is, String encoding) throws IOException {
InputStreamReader input = new InputStreamReader(is, encoding);
final int CHARS_PER_PAGE = 5000; //counting spaces
final char[] buffer = new char[CHARS_PER_PAGE];
StringBuilder output = new StringBuilder(CHARS_PER_PAGE);
for (int read = input.read(buffer, 0, buffer.length);
read != -1;
read = input.read(buffer, 0, buffer.length)) {
output.append(buffer, 0, read);
}
String text = output.toString();
return text;
}
public static void writeStringToFile(String string, String fileName, boolean append) throws IOException {
BufferedWriter out = new BufferedWriter(new FileWriter(fileName, append));
out.write(string);
out.close();
}
public static Class getCallerClass(int i) {
Class[] classContext = new SecurityManager() {
@Override public Class[] getClassContext() {
return super.getClassContext();
}
}.getClassContext();
if (classContext != null) {
for (int j = 0; j < classContext.length; j++) {
if (classContext[j] == Util.class) {
return classContext[i+j];
}
}
} else {
// SecurityManager.getClassContext() returns null on Android 4.0
try {
StackTraceElement[] classNames = Thread.currentThread().getStackTrace();
for (int j = 0; j < classNames.length; j++) {
if (Class.forName(classNames[j].getClassName()) == Util.class) {
return Class.forName(classNames[i+j].getClassName());
}
}
} catch (ClassNotFoundException e) { }
}
return null;
}
public static void main(String[] args) {
// System.out.println(Util.isBitSet((byte) 0x5f, 2)); // 0101 1111
// System.out.println(Util.isBitSet((byte) 0x9f, 2)); // 1001 1111
//
// System.out.println(Util.byte2Short((byte) 0x6F, (byte) 0xEF));
// System.out.println(Util.short2Hex(Util.byte2Short((byte) 0x6F, (byte) 0xEF)));
//
// System.out.println(Util.byteArrayToInt(new byte[]{(byte) 0x6F, (byte) 0xEF}));
// System.out.println(Util.byteArrayToHexString(Util.intToByteArray(28655)));
//
// System.out.println(Util.byte2BinaryLiteral((byte) 0x00));
// System.out.println(Util.byte2BinaryLiteral((byte) 0x3F));
// System.out.println(Util.byte2BinaryLiteral((byte) 0x80));
// System.out.println(Util.byte2BinaryLiteral((byte) 0xAA));
// System.out.println(Util.byte2BinaryLiteral((byte) 0xFF));
//
// System.out.println(Util.byte2BinaryLiteral((byte) 0x8A));
// System.out.println(Util.byte2BinaryLiteral(Util.setBit((byte) 0x8A, 5, true)));
// System.out.println(Util.byte2BinaryLiteral(Util.setBit((byte) 0x8A, 8, false)));
//
// System.out.println(Util.byteArrayToLong(Util.fromHexString("7f ff ff ff ff ff ff ff"), 0, 8));
// System.out.println(Util.byteArrayToLong(Util.fromHexString("22 18 09 04 0b 00 e0 30 23 07 00 00 00 42 d2 85 4e 23 07 00 00 00 00 21 69 42"), 13, 4));
System.out.println(Util.prettyPrintHexNoWrap(Util.resizeArray(new byte[]{0x01}, 0)));
System.out.println(Util.prettyPrintHexNoWrap(Util.resizeArray(new byte[]{0x01}, 1)));
System.out.println(Util.prettyPrintHexNoWrap(Util.resizeArray(new byte[]{0x01}, 2)));
System.out.println(Util.prettyPrintHexNoWrap(Util.resizeArray(new byte[]{0x01, 0x02}, 1)));
System.out.println(Util.prettyPrintHexNoWrap(Util.resizeArray(new byte[]{0x01, 0x02}, 4)));
}
}

View File

@ -0,0 +1,58 @@
package com.cmobile.unifiedtms;
import com.haulmont.cuba.testsupport.TestContainer;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.util.ArrayList;
import java.util.Arrays;
public class TmsTestContainer extends TestContainer {
public TmsTestContainer() {
super();
//noinspection ArraysAsListWithZeroOrOneArgument
appComponents = new ArrayList<>(Arrays.asList(
// list add-ons here: "com.haulmont.reports", "com.haulmont.addon.bproc", etc.
"com.haulmont.cuba"
));
appPropertiesFiles = Arrays.asList(
// List the files defined in your web.xml
// in appPropertiesConfig context parameter of the core module
"com/cmobile/unifiedtms/app.properties",
// Add this file which is located in CUBA and defines some properties
// specifically for test environment. You can replace it with your own
// or add another one in the end.
"com/cmobile/unifiedtms/test-app.properties");
autoConfigureDataSource();
}
public static class Common extends TmsTestContainer {
public static final TmsTestContainer.Common INSTANCE = new TmsTestContainer.Common();
private static volatile boolean initialized;
private Common() {
}
@Override
public void beforeAll(ExtensionContext extensionContext) throws Exception {
if (!initialized) {
super.beforeAll(extensionContext);
initialized = true;
}
setupContext();
}
@SuppressWarnings("RedundantThrows")
@Override
public void afterAll(ExtensionContext extensionContext) throws Exception {
cleanupContext();
// never stops - do not call super
}
}
}

View File

@ -0,0 +1,49 @@
package com.cmobile.unifiedtms.core;
import com.cmobile.unifiedtms.TmsTestContainer;
import com.haulmont.cuba.core.EntityManager;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.Transaction;
import com.haulmont.cuba.core.TypedQuery;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.security.entity.User;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.RegisterExtension;
import java.util.List;
public class SampleIntegrationTest {
@RegisterExtension
public static TmsTestContainer cont = TmsTestContainer.Common.INSTANCE;
private static Metadata metadata;
private static Persistence persistence;
private static DataManager dataManager;
@BeforeAll
public static void beforeAll() throws Exception {
metadata = cont.metadata();
persistence = cont.persistence();
dataManager = AppBeans.get(DataManager.class);
}
@AfterAll
public static void afterAll() throws Exception {
}
@Test
public void testLoadUser() {
try (Transaction tx = persistence.createTransaction()) {
EntityManager em = persistence.getEntityManager();
TypedQuery<User> query = em.createQuery(
"select u from sec$User u where u.login = :userLogin", User.class);
query.setParameter("userLogin", "admin");
List<User> users = query.getResultList();
tx.commit();
Assertions.assertEquals(1, users.size());
}
}
}

View File

@ -0,0 +1,8 @@
cuba.springContextConfig = +com/cmobile/unifiedtms/spring.xml \
com/haulmont/cuba/testsupport/test-spring.xml \
com/cmobile/unifiedtms/test-spring.xml
cuba.confDir=${user.dir}/build/test-home/${cuba.webContextName}/conf
cuba.logDir=${user.dir}/build/test-home/${cuba.webContextName}/logs
cuba.tempDir=${user.dir}/build/test-home/${cuba.webContextName}/temp
cuba.dataDir=${user.dir}/build/test-home/${cuba.webContextName}/work

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans">
<!-- Override existing beans or define new bean definitions required for tests -->
<!-- <bean id="cuba_Emailer" class="com.haulmont.cuba.testsupport.TestEmailer"/> -->
</beans>

View File

@ -0,0 +1,6 @@
<Context>
<!-- Switch off session serialization -->
<Manager pathname=""/>
</Context>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- Application properties config files -->
<context-param>
<param-name>appPropertiesConfig</param-name>
<param-value>
classpath:com/cmobile/unifiedtms/app.properties
/WEB-INF/local.app.properties
"file:${app.home}/local.app.properties"
</param-value>
</context-param>
<!--Application components-->
<context-param>
<param-name>appComponents</param-name>
<param-value>com.haulmont.cuba com.haulmont.addon.sdbmt com.haulmont.addon.helium com.haulmont.addon.restapi
com.haulmont.addon.dashboard com.haulmont.charts com.haulmont.fts com.haulmont.addon.emailtemplates
de.diedavids.cuba.dataimport com.cmobile.unifiedtms.ext ar.com.osmosys.pswdplus</param-value>
</context-param>
<listener>
<listener-class>com.haulmont.cuba.core.sys.AppContextLoader</listener-class>
</listener>
<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>com.haulmont.cuba.core.sys.remoting.RemotingServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/remoting/*</url-pattern>
</servlet-mapping>
</web-app>