From 582353e27760d4d76593794c9bf338db4817f282 Mon Sep 17 00:00:00 2001 From: Jaka Ramdani Date: Mon, 11 May 2026 19:59:10 +0700 Subject: [PATCH] initial import --- .gitignore | 11 + build.gradle | 228 ++ etc/war-logback.xml | 166 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 + gradlew.bat | 84 + .../db/init/postgres/01.ext-create-db.sql | 17 + .../init/postgres/01.pswdplus-create-db.sql | 18 + .../db/init/postgres/02.ext-create-db.sql | 1 + .../init/postgres/02.pswdplus-create-db.sql | 5 + .../core/db/init/postgres/10.create-db.sql | 605 ++++ .../core/db/init/postgres/20.create-db.sql | 126 + .../core/db/init/postgres/30.create-db.sql | 1 + ...51002-0-dropDeviceModelApplicationLink.sql | 1 + ...pDeviceModelApplicationLink_DropScript.sql | 1 + .../25/10/251002-1-updateDeleteTaskLog.sql | 1 + .../25/10/251002-1-updateDiagnosticInfo.sql | 1 + .../25/10/251002-1-updateDownloadTaskLog.sql | 1 + .../25/10/251002-1-updateTerminalLink.sql | 1 + .../25/10/251002-2-updateDeleteTaskLog01.sql | 1 + ...1002-2-updateDeviceProfileAcquirerLink.sql | 2 + .../25/10/251002-2-updateDiagnosticInfo.sql | 1 + ...1002-2-updateDiagnosticInfo_DropScript.sql | 1 + .../10/251002-2-updateDownloadTaskLog01.sql | 1 + .../25/10/251002-2-updateHeartBeat.sql | 3 + .../25/10/251002-2-updateHeartBeat01.sql | 2 + .../251002-2-updateHeartBeat_DropScript.sql | 1 + .../25/10/251002-2-updateTerminal.sql | 7 + .../25/10/251002-2-updateTerminalLink01.sql | 1 + .../10/251002-2-updateTerminal_DropScript.sql | 6 + .../10/251002-2-updateTmsextTerminalExt.sql | 2 + ...2-2-updateTmsextTerminalExt_DropScript.sql | 2 + ...60511-1-createTerminalGroupImportStage.sql | 15 + ...60511-2-updateTerminalGroupImportStage.sql | 1 + .../com/cmobile/unifiedtms/MqttConfig.java | 48 + .../src/com/cmobile/unifiedtms/Singleton.java | 30 + .../src/com/cmobile/unifiedtms/app.properties | 46 + .../unifiedtms/config/LicenseConfig.java | 16 + .../core/config/EchoTestConfig.java | 24 + .../core/config/ExtendedConfig.java | 21 + .../core/config/FileDownloadConfig.java | 16 + .../core/config/TerminalUpdateConfig.java | 25 + .../core/mqtt/BlindTrustManager.java | 23 + .../unifiedtms/core/mqtt/MqttConnector.java | 265 ++ .../mqtt/listener/DeleteTaskAckListener.java | 219 ++ .../mqtt/listener/DeviceInitListener.java | 135 + .../mqtt/listener/DiagnosticInfoListener.java | 197 ++ .../listener/DownloadTaskAckListener.java | 223 ++ .../core/mqtt/listener/EchoListener.java | 50 + .../core/mqtt/listener/HeartBeatListener.java | 120 + .../listener/IncomingMessageListener.java | 10 + .../listener/PendingTaskPushListener.java | 296 ++ .../core/security/MyLoginEventListener.java | 65 + .../UserSessionExistsAccessChecker.java | 49 + .../core/security/messages.properties | 1 + .../core/security/messages_in_ID.properties | 1 + .../core/src/com/cmobile/unifiedtms/fts.xml | 35 + .../listeners/AppLifecycleEventListener.java | 69 + .../unifiedtms/service/APIServiceBean.java | 2821 +++++++++++++++++ .../unifiedtms/service/ApkServiceBean.java | 32 + .../service/ChartDataServiceBean.java | 96 + .../service/DeleteTaskServiceBean.java | 226 ++ .../service/DeviceInitServiceBean.java | 130 + .../service/DownloadTaskServiceBean.java | 335 ++ .../unifiedtms/service/EchoServiceBean.java | 51 + .../unifiedtms/service/FileServiceBean.java | 248 ++ .../service/HeartBeatServiceBean.java | 18 + .../service/LicenseServiceBean.java | 182 ++ .../service/NumericInfoWidgetServiceBean.java | 296 ++ .../unifiedtms/service/ReportServiceBean.java | 1646 ++++++++++ .../service/ResponseCodeServiceBean.java | 118 + .../service/TerminalExtServiceBean.java | 102 + .../TerminalGroupImporterServiceBean.java | 461 +++ .../service/TerminalImporterServiceBean.java | 811 +++++ .../service/TerminalServiceBean.java | 80 + .../controllers/TerminalController.java | 82 + .../unifiedtms/service/messages.properties | 9 + .../service/messages_in_ID.properties | 9 + .../src/com/cmobile/unifiedtms/spring.xml | 8 + .../com/cmobile/unifiedtms/utils/ISOUtil.java | 32 + .../unifiedtms/utils/TerminalUpdateCache.java | 85 + .../cmobile/unifiedtms/utils/XlsHelper.java | 175 + modules/core/src/sasc/emv/EMVTags.java | 240 ++ .../sasc/emv/IssuerIdentificationNumber.java | 59 + modules/core/src/sasc/iso7816/BERTLV.java | 125 + .../src/sasc/iso7816/SmartCardException.java | 33 + .../core/src/sasc/iso7816/TLVException.java | 33 + modules/core/src/sasc/iso7816/TLVUtil.java | 275 ++ modules/core/src/sasc/iso7816/Tag.java | 27 + .../core/src/sasc/iso7816/TagAndLength.java | 51 + modules/core/src/sasc/iso7816/TagImpl.java | 141 + modules/core/src/sasc/iso7816/TagType.java | 6 + .../core/src/sasc/iso7816/TagValueType.java | 5 + .../core/src/sasc/util/ByteArrayWrapper.java | 56 + modules/core/src/sasc/util/Util.java | 689 ++++ .../cmobile/unifiedtms/TmsTestContainer.java | 58 + .../core/SampleIntegrationTest.java | 49 + .../cmobile/unifiedtms/test-app.properties | 8 + .../com/cmobile/unifiedtms/test-spring.xml | 8 + modules/core/web/META-INF/context.xml | 6 + modules/core/web/WEB-INF/web.xml | 38 + .../com/cmobile/unifiedtms/app-component.xml | 30 + .../unifiedtms/config/BroadcastConfig.java | 16 + .../unifiedtms/config/ReportConfig.java | 48 + .../unifiedtms/entity/Application.java | 156 + .../unifiedtms/entity/ApplicationSimple.java | 106 + .../com/cmobile/unifiedtms/entity/City.java | 44 + .../unifiedtms/entity/ContactPerson.java | 93 + .../cmobile/unifiedtms/entity/Country.java | 40 + .../cmobile/unifiedtms/entity/DeleteTask.java | 100 + .../unifiedtms/entity/DeleteTaskLog.java | 171 + .../unifiedtms/entity/DeviceModel.java | 66 + .../unifiedtms/entity/DeviceProfile.java | 303 ++ .../unifiedtms/entity/DeviceProfileApp.java | 45 + .../unifiedtms/entity/DiagnosticInfo.java | 224 ++ .../entity/DiagnosticInfoReport.java | 419 +++ .../cmobile/unifiedtms/entity/District.java | 44 + .../unifiedtms/entity/DownloadTask.java | 150 + .../unifiedtms/entity/DownloadTaskLog.java | 172 + .../unifiedtms/entity/ExportReportBean.java | 45 + .../cmobile/unifiedtms/entity/HeartBeat.java | 166 + .../unifiedtms/entity/HeartbeatSummary.java | 244 ++ .../unifiedtms/entity/LicenseModel.java | 213 ++ .../cmobile/unifiedtms/entity/Merchant.java | 107 + .../unifiedtms/entity/MerchantType.java | 39 + .../unifiedtms/entity/ResponseCode.java | 53 + .../com/cmobile/unifiedtms/entity/States.java | 44 + .../cmobile/unifiedtms/entity/Terminal.java | 343 ++ .../unifiedtms/entity/TerminalAckUpdate.java | 108 + .../unifiedtms/entity/TerminalGroup.java | 56 + .../entity/TerminalGroupImport.java | 67 + .../unifiedtms/entity/TerminalHeartBeat.java | 164 + .../unifiedtms/entity/TerminalImportBean.java | 209 ++ .../entity/TerminalLastDiagnosticInfo.java | 305 ++ .../entity/TerminalLastHeartBeat.java | 197 ++ .../entity/TerminalLastStepUpdate.java | 75 + .../unifiedtms/entity/TerminalLastUpdate.java | 89 + .../unifiedtms/entity/TerminalLink.java | 109 + .../unifiedtms/entity/TerminalProfiling.java | 96 + .../entity/TerminalProfilingItem.java | 236 ++ .../unifiedtms/entity/TerminalReport.java | 477 +++ .../cmobile/unifiedtms/entity/VHeartBeat.java | 168 + .../entity/chartdata/CountryGrowth.java | 41 + .../entity/chartdata/PieChartData.java | 42 + .../entity/enums/DeleteTaskActivity.java | 37 + .../entity/enums/DownloadTaskActivity.java | 40 + .../entity/enums/DownloadTaskType.java | 32 + .../entity/enums/DownloadTimeType.java | 32 + .../unifiedtms/entity/enums/ExportType.java | 32 + .../entity/enums/InstallationTimeType.java | 32 + .../unifiedtms/entity/enums/ReportType.java | 34 + .../entity/enums/TaskNotificationType.java | 32 + .../unifiedtms/entity/enums/TaskStatus.java | 34 + .../entity/enums/TerminalHeartBeatStatus.java | 33 + .../unifiedtms/entity/enums/TrxType.java | 34 + .../entity/enums/messages.properties | 45 + .../unifiedtms/entity/messages.properties | 358 +++ .../unifiedtms/entity/misc/CellInfo.java | 55 + .../entity/misc/ExpirableObject.java | 26 + .../entity/misc/FileDownloadWrapper.java | 36 + .../TerminalGroupImportObjectWrapper.java | 60 + .../misc/TerminalImporterObjectWrapper.java | 30 + .../entity/misc/TerminalUpdateCacheObj.java | 61 + .../entity/restmodel/DiagnosticInfo.java | 214 ++ .../entity/restmodel/HeartBeatRequest.java | 87 + .../entity/restmodel/LocationInfo.java | 43 + .../request/AckParameterRequest.java | 76 + .../request/AddApplicationRequest.java | 91 + .../request/AddDownloadTaskRequest.java | 82 + .../restmodel/request/AddProfileRequest.java | 13 + .../request/AddTerminalGroupRequest.java | 42 + .../restmodel/request/AddTerminalRequest.java | 72 + .../restmodel/request/CheckUpdateRequest.java | 37 + .../restmodel/request/DeleteRequest.java | 20 + .../restmodel/request/DetailRequest.java | 20 + .../request/EditTerminalGroupRequest.java | 18 + .../request/EditTerminalRequest.java | 18 + .../restmodel/request/InitProfileRequest.java | 37 + .../restmodel/request/PaginatedRequest.java | 37 + .../request/TerminalAssignRequest.java | 33 + .../request/TerminalDetailRequest.java | 20 + .../restmodel/result/BaseDetailExtResult.java | 43 + .../restmodel/result/BaseDetailResult.java | 24 + .../entity/restmodel/result/BaseIdResult.java | 24 + .../restmodel/result/BaseListExtResult.java | 56 + .../restmodel/result/BaseListResult.java | 31 + .../restmodel/result/BasePaginatedResult.java | 76 + .../entity/restmodel/result/BaseResult.java | 38 + .../restmodel/result/data/AppSimple.java | 35 + .../result/data/CheckParameterUpdateExt.java | 79 + .../result/data/DeviceModelDetail.java | 69 + .../result/data/DeviceModelSimple.java | 52 + .../result/data/DeviceProfileDetail.java | 130 + .../result/data/DeviceProfileSimple.java | 58 + .../result/data/DiagnosticSimple.java | 164 + .../result/data/DownloadTaskDetail.java | 106 + .../result/data/DownloadTaskSimple.java | 37 + .../entity/restmodel/result/data/Feature.java | 33 + .../restmodel/result/data/HearbeatSimple.java | 119 + .../restmodel/result/data/MerchantSimple.java | 51 + .../result/data/ResponseCodeSimple.java | 60 + .../restmodel/result/data/TerminalDetail.java | 78 + .../result/data/TerminalExtAddressSimple.java | 86 + .../result/data/TerminalFeatures.java | 105 + .../result/data/TerminalGroupSimple.java | 62 + .../restmodel/result/data/TerminalSimple.java | 78 + .../restmodel/result/data/UpdateAidData.java | 16 + .../restmodel/result/data/UpdateCapkData.java | 16 + .../restmodel/result/data/UpdateCardData.java | 16 + .../result/data/UpdateContactlessAidData.java | 16 + .../result/data/UpdateTerminalData.java | 71 + .../ImportFileEofEvaluationException.java | 25 + .../src/com/cmobile/unifiedtms/metadata.xml | 8 + .../com/cmobile/unifiedtms/persistence.xml | 38 + .../security/UserSessionExistsException.java | 21 + .../unifiedtms/service/APIService.java | 86 + .../unifiedtms/service/ApkService.java | 9 + .../unifiedtms/service/ChartDataService.java | 12 + .../unifiedtms/service/DeleteTaskService.java | 10 + .../unifiedtms/service/DeviceInitService.java | 12 + .../service/DownloadTaskService.java | 11 + .../unifiedtms/service/EchoService.java | 7 + .../unifiedtms/service/FileService.java | 18 + .../unifiedtms/service/HeartBeatService.java | 10 + .../unifiedtms/service/LicenseService.java | 15 + .../service/NumericInfoWidgetService.java | 7 + .../unifiedtms/service/ReportService.java | 18 + .../service/ResponseCodeService.java | 13 + .../service/TerminalExtService.java | 8 + .../service/TerminalGroupImporterService.java | 14 + .../service/TerminalImporterService.java | 25 + .../unifiedtms/service/TerminalService.java | 10 + .../src/com/cmobile/unifiedtms/views.xml | 791 +++++ .../cmobile/unifiedtms/TmsTestContainer.java | 58 + .../core/SampleIntegrationTest.java | 49 + .../cmobile/unifiedtms/test-app.properties | 8 + .../com/cmobile/unifiedtms/test-spring.xml | 8 + .../web/private/cache/retriever/catalog.xml | 0 .../unifiedtms/rest-dispatcher-spring.xml | 34 + .../unifiedtms/rest-json-transformations.xml | 12 + .../com/cmobile/unifiedtms/rest-queries.xml | 8 + .../com/cmobile/unifiedtms/rest-services.xml | 133 + .../com/cmobile/unifiedtms/web-app.properties | 68 + .../unifiedtms/web-dispatcher-spring.xml | 7 + .../src/com/cmobile/unifiedtms/web-menu.xml | 78 + .../cmobile/unifiedtms/web-permissions.xml | 3 + .../com/cmobile/unifiedtms/web-screens.xml | 7 + .../src/com/cmobile/unifiedtms/web-spring.xml | 40 + .../web/filter/BlockHttpMethodFilter.java | 45 + .../filter/VaadinBlockDirListingFilter.java | 52 + .../unifiedtms/web/messages.properties | 62 + .../unifiedtms/web/messages_id_ID.properties | 5 + .../web/screens/AppLoginScreen.java | 70 + .../web/screens/DashboardScreen.java | 15 + .../unifiedtms/web/screens/ExtMainScreen.java | 11 + .../unifiedtms/web/screens/SampleChart.java | 44 + .../web/screens/SimulateExceptionScreen.java | 16 + .../web/screens/app-login-screen.xml | 90 + .../application/ApplicationBrowse.java | 11 + .../screens/application/ApplicationEdit.java | 63 + .../application/application-browse.xml | 54 + .../screens/application/application-edit.xml | 34 + .../screens/application/messages.properties | 2 + .../ApplicationSimpleEdit.java | 19 + .../application-simple-edit.xml | 29 + .../applicationsimple/messages.properties | 1 + .../messages_id_ID.properties | 0 .../changepasswd/ExtChangePasswordDialog.java | 49 + .../ext-change-password-dialog.xml | 32 + .../screens/changepasswd/messages.properties | 13 + .../changepasswd/messages_id_ID.properties | 3 + .../web/screens/city/CityBrowse.java | 11 + .../unifiedtms/web/screens/city/CityEdit.java | 11 + .../web/screens/city/city-browse.xml | 54 + .../unifiedtms/web/screens/city/city-edit.xml | 34 + .../web/screens/city/messages.properties | 2 + .../contactperson/ContactPersonBrowse.java | 11 + .../contactperson/ContactPersonEdit.java | 11 + .../contactperson/contact-person-browse.xml | 54 + .../contactperson/contact-person-edit.xml | 31 + .../screens/contactperson/messages.properties | 3 + .../web/screens/country/CountryBrowse.java | 14 + .../web/screens/country/CountryEdit.java | 11 + .../web/screens/country/country-browse.xml | 58 + .../web/screens/country/country-edit.xml | 27 + .../web/screens/country/messages.properties | 2 + .../web/screens/dashboard-screen.xml | 12 + .../screens/deletetask/DeleteTaskBrowse.java | 55 + .../screens/deletetask/DeleteTaskEdit.java | 55 + .../screens/deletetask/delete-task-browse.xml | 52 + .../screens/deletetask/delete-task-edit.xml | 96 + .../screens/deletetask/messages.properties | 5 + .../deletetask/messages_id_ID.properties | 0 .../devicemodel/DeviceModelBrowse.java | 11 + .../screens/devicemodel/DeviceModelEdit.java | 11 + .../devicemodel/device-model-browse.xml | 55 + .../screens/devicemodel/device-model-edit.xml | 31 + .../screens/devicemodel/messages.properties | 2 + .../deviceprofile/DeviceProfileBrowse.java | 11 + .../deviceprofile/DeviceProfileEdit.java | 28 + .../deviceprofile/device-profile-browse.xml | 66 + .../deviceprofile/device-profile-edit.xml | 99 + .../screens/deviceprofile/messages.properties | 4 + .../deviceprofile/messages_id_ID.properties | 0 .../DeviceProfileAppEdit.java | 11 + .../device-profile-app-edit.xml | 28 + .../deviceprofileapp/messages.properties | 1 + .../messages_id_ID.properties | 0 .../diagnosticinfo/DiagnosticInfoBrowse.java | 28 + .../diagnosticinfo/DiagnosticInfoEdit.java | 10 + .../diagnosticinfo/DiagnosticInfoView.java | 17 + .../diagnosticinfo/diagnostic-info-browse.xml | 60 + .../diagnosticinfo/diagnostic-info-edit.xml | 53 + .../diagnosticinfo/diagnostic-info-view.xml | 67 + .../diagnosticinfo/messages.properties | 5 + .../diagnosticinfo/messages_id_ID.properties | 0 .../web/screens/district/DistrictBrowse.java | 11 + .../web/screens/district/DistrictEdit.java | 11 + .../web/screens/district/district-browse.xml | 54 + .../web/screens/district/district-edit.xml | 34 + .../web/screens/district/messages.properties | 2 + .../downloadtask/DownloadTaskBrowse.java | 54 + .../downloadtask/DownloadTaskEdit.java | 59 + .../downloadtask/download-task-browse.xml | 52 + .../downloadtask/download-task-edit.xml | 102 + .../screens/downloadtask/messages.properties | 5 + .../downloadtask/messages_id_ID.properties | 0 .../web/screens/ext-main-screen.xml | 80 + .../screens/formatter/CelciusFormatter.java | 12 + .../screens/formatter/FileSizeFormatter.java | 30 + .../formatter/PercentageFormatter.java | 12 + .../fragments/DownloadStatsWidget.java | 87 + .../screens/fragments/NumericInfoWidget.java | 93 + .../fragments/download-stats-widget.xml | 7 + .../web/screens/fragments/messages.properties | 1 + .../screens/fragments/numeric-info-widget.xml | 11 + .../screens/heartbeat/HeartBeatBrowse.java | 11 + .../screens/heartbeat/heart-beat-browse.xml | 51 + .../web/screens/heartbeat/messages.properties | 1 + .../heartbeat/messages_id_ID.properties | 0 .../HeartbeatSummaryBrowse.java | 207 ++ .../heartbeat-summary-browse.xml | 32 + .../heartbeatsummary/messages.properties | 4 + .../messages_id_ID.properties | 0 .../web/screens/license/LicenseUpdate.java | 191 ++ .../web/screens/license/LicenseViewer.java | 172 + .../web/screens/license/license-update.xml | 27 + .../web/screens/license/license-viewer.xml | 110 + .../web/screens/license/messages.properties | 14 + .../screens/license/messages_id_ID.properties | 14 + .../web/screens/merchant/MerchantBrowse.java | 11 + .../web/screens/merchant/MerchantEdit.java | 11 + .../web/screens/merchant/merchant-browse.xml | 58 + .../web/screens/merchant/merchant-edit.xml | 65 + .../web/screens/merchant/messages.properties | 3 + .../merchanttype/MerchantTypeBrowse.java | 11 + .../merchanttype/MerchantTypeEdit.java | 11 + .../merchanttype/merchant-type-browse.xml | 54 + .../merchanttype/merchant-type-edit.xml | 29 + .../screens/merchanttype/messages.properties | 2 + .../web/screens/messages.properties | 7 + .../web/screens/messages_id_ID.properties | 0 .../web/screens/report/messages.properties | 29 + .../responsecode/ResponseCodeBrowse.java | 73 + .../responsecode/ResponseCodeEdit.java | 11 + .../screens/responsecode/messages.properties | 2 + .../responsecode/messages_id_ID.properties | 0 .../responsecode/response-code-browse.xml | 62 + .../responsecode/response-code-edit.xml | 30 + .../unifiedtms/web/screens/sample-chart.xml | 47 + .../web/screens/simulate-exception-screen.xml | 7 + .../web/screens/states/StatesBrowse.java | 11 + .../web/screens/states/StatesEdit.java | 11 + .../web/screens/states/messages.properties | 2 + .../web/screens/states/states-browse.xml | 54 + .../web/screens/states/states-edit.xml | 32 + .../web/screens/terminal/TerminalBrowse.java | 72 + .../web/screens/terminal/TerminalEdit.java | 53 + .../web/screens/terminal/messages.properties | 2 + .../terminal/messages_id_ID.properties | 0 .../web/screens/terminal/terminal-browse.xml | 60 + .../web/screens/terminal/terminal-edit.xml | 71 + .../DuplicateTerminalInputDialog.java | 10 + .../duplicate-terminal-input-dialog.xml | 26 + .../screens/terminalext/messages.properties | 3 + .../terminalext/messages_id_ID.properties | 1 + .../terminalgroup/TerminalGroupBrowse.java | 11 + .../terminalgroup/TerminalGroupEdit.java | 108 + .../screens/terminalgroup/messages.properties | 3 + .../terminalgroup/messages_id_ID.properties | 1 + .../terminalgroup/terminal-group-browse.xml | 52 + .../terminalgroup/terminal-group-edit.xml | 55 + .../TerminalGroupImportBrowse.java | 156 + .../terminalgroupimport/messages.properties | 11 + .../messages_id_ID.properties | 5 + .../terminal-group-import-browse.xml | 78 + .../TerminalLastDiagnosticInfoBrowse.java | 34 + .../TerminalLastDiagnosticInfoEdit.java | 49 + .../messages.properties | 5 + .../messages_id_ID.properties | 0 .../terminal-last-diagnostic-info-browse.xml | 59 + .../terminal-last-diagnostic-info-edit.xml | 70 + .../TerminalLastHeartBeatBrowse.java | 87 + .../TerminalLastHeartBeatMap.java | 106 + .../terminallastheartbeat/messages.properties | 2 + .../terminal-last-heart-beat-browse.xml | 89 + .../terminal-last-heart-beat-map.xml | 57 + .../terminallink/TerminalExtSimpleBrowse.java | 11 + .../terminallink/TerminalLinkBrowse.java | 11 + .../terminallink/TerminalLinkEdit.java | 85 + .../terminallink/TerminalSimpleBrowse.java | 11 + .../screens/terminallink/messages.properties | 6 + .../terminallink/messages_id_ID.properties | 0 .../terminal-ext-simple-browse.xml | 49 + .../terminallink/terminal-link-browse.xml | 52 + .../terminallink/terminal-link-edit.xml | 37 + .../terminallink/terminal-simple-browse.xml | 51 + .../terminalprofiling/TerminalProfiling.java | 185 ++ .../TerminalProfilingBrowse.java | 11 + .../TerminalProfilingEdit.java | 145 + .../terminalprofiling/messages.properties | 8 + .../messages_id_ID.properties | 0 .../terminal-profiling-browse.xml | 52 + .../terminal-profiling-edit.xml | 50 + .../terminalprofiling/terminal-profiling.xml | 24 + .../terminalreport/TerminalLinkLogBrowse.java | 11 + .../terminalreport/TerminalReportBrowse.java | 11 + .../terminalreport/TerminalReportNew.java | 116 + .../terminalreport/messages.properties | 10 + .../terminalreport/messages_id_ID.properties | 7 + .../terminal-link-log-browse.xml | 54 + .../terminalreport/terminal-report-browse.xml | 82 + .../terminalreport/terminal-report-new.xml | 41 + .../web/screens/user/ExtUserBrowser.java | 6 + .../web/screens/user/ExtUserEditor.java | 6 + .../web/screens/user/ext-user-browse.xml | 14 + .../web/screens/user/ext-user-edit.xml | 8 + .../web/screens/user/messages.properties | 1 + .../screens/user/messages_id_ID.properties | 1 + .../screens/vheartbeat/VHeartBeatBrowse.java | 100 + .../screens/vheartbeat/messages.properties | 10 + .../vheartbeat/messages_id_ID.properties | 1 + .../vheartbeat/v-heart-beat-browse.xml | 71 + .../unifiedtms/web/widget/messages.properties | 2 + .../themes/halo/branding/app-icon-login.png | Bin 0 -> 812 bytes .../themes/halo/branding/app-icon-menu.png | Bin 0 -> 1399 bytes .../com.cmobile.unifiedtms/app-component.scss | 5 + .../halo-ext-defaults.scss | 0 .../halo/com.cmobile.unifiedtms/halo-ext.scss | 127 + modules/web/themes/halo/cuba-icon-login.png | Bin 0 -> 799 bytes modules/web/themes/halo/favicon.ico | Bin 0 -> 12862 bytes modules/web/themes/halo/styles.scss | 11 + .../themes/havana/branding/app-icon-login.png | Bin 0 -> 812 bytes .../themes/havana/branding/app-icon-menu.png | Bin 0 -> 1399 bytes .../com.cmobile.unifiedtms/app-component.scss | 5 + .../havana-ext-defaults.scss | 0 .../com.cmobile.unifiedtms/havana-ext.scss | 98 + modules/web/themes/havana/favicon.ico | Bin 0 -> 12862 bytes modules/web/themes/havana/styles.scss | 11 + .../themes/hover/branding/app-icon-login.png | Bin 0 -> 812 bytes .../themes/hover/branding/app-icon-menu.png | Bin 0 -> 1399 bytes .../com.cmobile.unifiedtms/app-component.scss | 5 + .../hover-ext-defaults.scss | 0 .../com.cmobile.unifiedtms/hover-ext.scss | 82 + modules/web/themes/hover/favicon.ico | Bin 0 -> 12862 bytes modules/web/themes/hover/styles.scss | 11 + modules/web/web/META-INF/context.xml | 6 + .../VAADIN/brand-login-screen/background.png | Bin 0 -> 17194 bytes .../VAADIN/brand-login-screen/background.svg | 51 + .../brand-login-screen/cuba-icon-login.png | Bin 0 -> 799 bytes .../brand-login-screen/cuba-icon-login.svg | 33 + .../web/VAADIN/brand-login-screen/login.css | 129 + modules/web/web/WEB-INF/single-war-web.xml | 45 + modules/web/web/WEB-INF/web.xml | 111 + settings.gradle | 6 + sql/backup_view_terminal_last_hearbeat.sql | 16 + sql/diagnostic_infos.sql | 4 + studio-intellij.xml | 7 + 479 files changed, 32418 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 etc/war-logback.xml create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 modules/core/db/init/postgres/01.ext-create-db.sql create mode 100644 modules/core/db/init/postgres/01.pswdplus-create-db.sql create mode 100644 modules/core/db/init/postgres/02.ext-create-db.sql create mode 100644 modules/core/db/init/postgres/02.pswdplus-create-db.sql create mode 100644 modules/core/db/init/postgres/10.create-db.sql create mode 100644 modules/core/db/init/postgres/20.create-db.sql create mode 100644 modules/core/db/init/postgres/30.create-db.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink_DropScript.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-1-updateDeleteTaskLog.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-1-updateDiagnosticInfo.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-1-updateDownloadTaskLog.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-1-updateTerminalLink.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateDeleteTaskLog01.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateDeviceProfileAcquirerLink.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo_DropScript.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateDownloadTaskLog01.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat01.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat_DropScript.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateTerminal.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateTerminalLink01.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateTerminal_DropScript.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt.sql create mode 100644 modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt_DropScript.sql create mode 100644 modules/core/db/update/postgres/26/05/260511-1-createTerminalGroupImportStage.sql create mode 100644 modules/core/db/update/postgres/26/05/260511-2-updateTerminalGroupImportStage.sql create mode 100644 modules/core/src/com/cmobile/unifiedtms/MqttConfig.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/Singleton.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/app.properties create mode 100644 modules/core/src/com/cmobile/unifiedtms/config/LicenseConfig.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/config/EchoTestConfig.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/config/ExtendedConfig.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/config/FileDownloadConfig.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/config/TerminalUpdateConfig.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/BlindTrustManager.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/MqttConnector.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeleteTaskAckListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeviceInitListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DiagnosticInfoListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DownloadTaskAckListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/EchoListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/HeartBeatListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/IncomingMessageListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/PendingTaskPushListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/security/MyLoginEventListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/security/UserSessionExistsAccessChecker.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/security/messages.properties create mode 100644 modules/core/src/com/cmobile/unifiedtms/core/security/messages_in_ID.properties create mode 100644 modules/core/src/com/cmobile/unifiedtms/fts.xml create mode 100644 modules/core/src/com/cmobile/unifiedtms/listeners/AppLifecycleEventListener.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/APIServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/ApkServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/ChartDataServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/DeleteTaskServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/DeviceInitServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/DownloadTaskServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/EchoServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/FileServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/HeartBeatServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/LicenseServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/NumericInfoWidgetServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/ReportServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/ResponseCodeServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/TerminalExtServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/TerminalGroupImporterServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/TerminalImporterServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/TerminalServiceBean.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/controllers/TerminalController.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/messages.properties create mode 100644 modules/core/src/com/cmobile/unifiedtms/service/messages_in_ID.properties create mode 100644 modules/core/src/com/cmobile/unifiedtms/spring.xml create mode 100644 modules/core/src/com/cmobile/unifiedtms/utils/ISOUtil.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/utils/TerminalUpdateCache.java create mode 100644 modules/core/src/com/cmobile/unifiedtms/utils/XlsHelper.java create mode 100644 modules/core/src/sasc/emv/EMVTags.java create mode 100644 modules/core/src/sasc/emv/IssuerIdentificationNumber.java create mode 100644 modules/core/src/sasc/iso7816/BERTLV.java create mode 100644 modules/core/src/sasc/iso7816/SmartCardException.java create mode 100644 modules/core/src/sasc/iso7816/TLVException.java create mode 100644 modules/core/src/sasc/iso7816/TLVUtil.java create mode 100644 modules/core/src/sasc/iso7816/Tag.java create mode 100644 modules/core/src/sasc/iso7816/TagAndLength.java create mode 100644 modules/core/src/sasc/iso7816/TagImpl.java create mode 100644 modules/core/src/sasc/iso7816/TagType.java create mode 100644 modules/core/src/sasc/iso7816/TagValueType.java create mode 100644 modules/core/src/sasc/util/ByteArrayWrapper.java create mode 100644 modules/core/src/sasc/util/Util.java create mode 100644 modules/core/test/com/cmobile/unifiedtms/TmsTestContainer.java create mode 100644 modules/core/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java create mode 100644 modules/core/test/com/cmobile/unifiedtms/test-app.properties create mode 100644 modules/core/test/com/cmobile/unifiedtms/test-spring.xml create mode 100644 modules/core/web/META-INF/context.xml create mode 100644 modules/core/web/WEB-INF/web.xml create mode 100644 modules/global/src/com/cmobile/unifiedtms/app-component.xml create mode 100644 modules/global/src/com/cmobile/unifiedtms/config/BroadcastConfig.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/config/ReportConfig.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/Application.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/ApplicationSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/City.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/ContactPerson.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/Country.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DeleteTask.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DeleteTaskLog.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DeviceModel.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfile.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfileApp.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfo.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfoReport.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/District.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DownloadTask.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/DownloadTaskLog.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/ExportReportBean.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/HeartBeat.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/HeartbeatSummary.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/LicenseModel.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/Merchant.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/MerchantType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/ResponseCode.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/States.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/Terminal.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalAckUpdate.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroup.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroupImport.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalHeartBeat.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalImportBean.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastDiagnosticInfo.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastHeartBeat.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastStepUpdate.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastUpdate.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalLink.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfiling.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfilingItem.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/TerminalReport.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/VHeartBeat.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/chartdata/CountryGrowth.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/chartdata/PieChartData.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/DeleteTaskActivity.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskActivity.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTimeType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/ExportType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/InstallationTimeType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/ReportType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskNotificationType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskStatus.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/TerminalHeartBeatStatus.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/TrxType.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/enums/messages.properties create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/messages.properties create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/misc/CellInfo.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/misc/ExpirableObject.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/misc/FileDownloadWrapper.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalGroupImportObjectWrapper.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalImporterObjectWrapper.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalUpdateCacheObj.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/DiagnosticInfo.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/HeartBeatRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/LocationInfo.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AckParameterRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddApplicationRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddDownloadTaskRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddProfileRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalGroupRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/CheckUpdateRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DeleteRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DetailRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalGroupRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/InitProfileRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/PaginatedRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalAssignRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalDetailRequest.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailExtResult.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailResult.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseIdResult.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListExtResult.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListResult.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BasePaginatedResult.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseResult.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/AppSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/CheckParameterUpdateExt.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelDetail.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileDetail.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DiagnosticSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskDetail.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/Feature.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/HearbeatSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/MerchantSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/ResponseCodeSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalDetail.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalExtAddressSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalFeatures.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalGroupSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalSimple.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateAidData.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCapkData.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCardData.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateContactlessAidData.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateTerminalData.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/exception/ImportFileEofEvaluationException.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/metadata.xml create mode 100644 modules/global/src/com/cmobile/unifiedtms/persistence.xml create mode 100644 modules/global/src/com/cmobile/unifiedtms/security/UserSessionExistsException.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/APIService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/ApkService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/ChartDataService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/DeleteTaskService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/DeviceInitService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/DownloadTaskService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/EchoService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/FileService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/HeartBeatService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/LicenseService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/NumericInfoWidgetService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/ReportService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/ResponseCodeService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/TerminalExtService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/TerminalGroupImporterService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/TerminalImporterService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/service/TerminalService.java create mode 100644 modules/global/src/com/cmobile/unifiedtms/views.xml create mode 100644 modules/test/com/cmobile/unifiedtms/TmsTestContainer.java create mode 100644 modules/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java create mode 100644 modules/test/com/cmobile/unifiedtms/test-app.properties create mode 100644 modules/test/com/cmobile/unifiedtms/test-spring.xml create mode 100644 modules/web/private/cache/retriever/catalog.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/rest-dispatcher-spring.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/rest-json-transformations.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/rest-queries.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/rest-services.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web-app.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web-dispatcher-spring.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web-menu.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web-permissions.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web-screens.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web-spring.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/filter/BlockHttpMethodFilter.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/filter/VaadinBlockDirListingFilter.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/AppLoginScreen.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/DashboardScreen.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/ExtMainScreen.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/SampleChart.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/SimulateExceptionScreen.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/app-login-screen.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/application/ApplicationBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/application/ApplicationEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/application/application-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/application/application-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/application/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/applicationsimple/ApplicationSimpleEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/applicationsimple/application-simple-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/applicationsimple/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/applicationsimple/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/changepasswd/ExtChangePasswordDialog.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/changepasswd/ext-change-password-dialog.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/changepasswd/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/changepasswd/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/city/CityBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/city/CityEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/city/city-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/city/city-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/city/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/contactperson/ContactPersonBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/contactperson/ContactPersonEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/contactperson/contact-person-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/contactperson/contact-person-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/contactperson/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/country/CountryBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/country/CountryEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/country/country-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/country/country-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/country/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/dashboard-screen.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deletetask/DeleteTaskBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deletetask/DeleteTaskEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deletetask/delete-task-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deletetask/delete-task-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deletetask/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deletetask/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/devicemodel/DeviceModelBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/devicemodel/DeviceModelEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/devicemodel/device-model-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/devicemodel/device-model-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/devicemodel/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofile/DeviceProfileBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofile/DeviceProfileEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofile/device-profile-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofile/device-profile-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofile/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofile/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofileapp/DeviceProfileAppEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofileapp/device-profile-app-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofileapp/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/deviceprofileapp/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/DiagnosticInfoBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/DiagnosticInfoEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/DiagnosticInfoView.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/diagnostic-info-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/diagnostic-info-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/diagnostic-info-view.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/diagnosticinfo/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/district/DistrictBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/district/DistrictEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/district/district-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/district/district-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/district/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/downloadtask/DownloadTaskBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/downloadtask/DownloadTaskEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/downloadtask/download-task-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/downloadtask/download-task-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/downloadtask/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/downloadtask/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/ext-main-screen.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/formatter/CelciusFormatter.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/formatter/FileSizeFormatter.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/formatter/PercentageFormatter.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/fragments/DownloadStatsWidget.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/fragments/NumericInfoWidget.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/fragments/download-stats-widget.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/fragments/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/fragments/numeric-info-widget.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeat/HeartBeatBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeat/heart-beat-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeat/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeat/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeatsummary/HeartbeatSummaryBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeatsummary/heartbeat-summary-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeatsummary/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/heartbeatsummary/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/license/LicenseUpdate.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/license/LicenseViewer.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/license/license-update.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/license/license-viewer.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/license/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/license/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchant/MerchantBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchant/MerchantEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchant/merchant-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchant/merchant-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchant/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchanttype/MerchantTypeBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchanttype/MerchantTypeEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchanttype/merchant-type-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchanttype/merchant-type-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/merchanttype/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/report/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/responsecode/ResponseCodeBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/responsecode/ResponseCodeEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/responsecode/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/responsecode/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/responsecode/response-code-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/responsecode/response-code-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/sample-chart.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/simulate-exception-screen.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/states/StatesBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/states/StatesEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/states/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/states/states-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/states/states-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminal/TerminalBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminal/TerminalEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminal/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminal/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminal/terminal-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminal/terminal-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalext/DuplicateTerminalInputDialog.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalext/duplicate-terminal-input-dialog.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalext/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalext/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroup/TerminalGroupBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroup/TerminalGroupEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroup/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroup/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroup/terminal-group-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroup/terminal-group-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroupimport/TerminalGroupImportBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroupimport/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroupimport/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalgroupimport/terminal-group-import-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastdiagnosticinfo/TerminalLastDiagnosticInfoBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastdiagnosticinfo/TerminalLastDiagnosticInfoEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastdiagnosticinfo/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastdiagnosticinfo/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastdiagnosticinfo/terminal-last-diagnostic-info-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastdiagnosticinfo/terminal-last-diagnostic-info-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastheartbeat/TerminalLastHeartBeatBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastheartbeat/TerminalLastHeartBeatMap.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastheartbeat/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastheartbeat/terminal-last-heart-beat-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallastheartbeat/terminal-last-heart-beat-map.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/TerminalExtSimpleBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/TerminalLinkBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/TerminalLinkEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/TerminalSimpleBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/terminal-ext-simple-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/terminal-link-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/terminal-link-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminallink/terminal-simple-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/TerminalProfiling.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/TerminalProfilingBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/TerminalProfilingEdit.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/terminal-profiling-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/terminal-profiling-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalprofiling/terminal-profiling.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/TerminalLinkLogBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/TerminalReportBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/TerminalReportNew.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/terminal-link-log-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/terminal-report-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/terminalreport/terminal-report-new.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/user/ExtUserBrowser.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/user/ExtUserEditor.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/user/ext-user-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/user/ext-user-edit.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/user/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/user/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/vheartbeat/VHeartBeatBrowse.java create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/vheartbeat/messages.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/vheartbeat/messages_id_ID.properties create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/screens/vheartbeat/v-heart-beat-browse.xml create mode 100644 modules/web/src/com/cmobile/unifiedtms/web/widget/messages.properties create mode 100644 modules/web/themes/halo/branding/app-icon-login.png create mode 100644 modules/web/themes/halo/branding/app-icon-menu.png create mode 100644 modules/web/themes/halo/com.cmobile.unifiedtms/app-component.scss create mode 100644 modules/web/themes/halo/com.cmobile.unifiedtms/halo-ext-defaults.scss create mode 100644 modules/web/themes/halo/com.cmobile.unifiedtms/halo-ext.scss create mode 100644 modules/web/themes/halo/cuba-icon-login.png create mode 100644 modules/web/themes/halo/favicon.ico create mode 100644 modules/web/themes/halo/styles.scss create mode 100644 modules/web/themes/havana/branding/app-icon-login.png create mode 100644 modules/web/themes/havana/branding/app-icon-menu.png create mode 100644 modules/web/themes/havana/com.cmobile.unifiedtms/app-component.scss create mode 100644 modules/web/themes/havana/com.cmobile.unifiedtms/havana-ext-defaults.scss create mode 100644 modules/web/themes/havana/com.cmobile.unifiedtms/havana-ext.scss create mode 100644 modules/web/themes/havana/favicon.ico create mode 100644 modules/web/themes/havana/styles.scss create mode 100644 modules/web/themes/hover/branding/app-icon-login.png create mode 100644 modules/web/themes/hover/branding/app-icon-menu.png create mode 100644 modules/web/themes/hover/com.cmobile.unifiedtms/app-component.scss create mode 100644 modules/web/themes/hover/com.cmobile.unifiedtms/hover-ext-defaults.scss create mode 100644 modules/web/themes/hover/com.cmobile.unifiedtms/hover-ext.scss create mode 100644 modules/web/themes/hover/favicon.ico create mode 100644 modules/web/themes/hover/styles.scss create mode 100644 modules/web/web/META-INF/context.xml create mode 100644 modules/web/web/VAADIN/brand-login-screen/background.png create mode 100644 modules/web/web/VAADIN/brand-login-screen/background.svg create mode 100644 modules/web/web/VAADIN/brand-login-screen/cuba-icon-login.png create mode 100644 modules/web/web/VAADIN/brand-login-screen/cuba-icon-login.svg create mode 100644 modules/web/web/VAADIN/brand-login-screen/login.css create mode 100644 modules/web/web/WEB-INF/single-war-web.xml create mode 100644 modules/web/web/WEB-INF/web.xml create mode 100644 settings.gradle create mode 100644 sql/backup_view_terminal_last_hearbeat.sql create mode 100644 sql/diagnostic_infos.sql create mode 100644 studio-intellij.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b641777 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.gradle +.studio +*.ipr +*.iml +*.iws +build/* +deploy/* +modules/*/build/* +.idea/* +out +test-run \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..b7032d2 --- /dev/null +++ b/build.gradle @@ -0,0 +1,228 @@ + +buildscript { + ext.cubaVersion = '7.2.6' + repositories { + mavenLocal() + maven { + url 'https://repo.cuba-platform.com/content/groups/work' + credentials { + username(rootProject.hasProperty('repoUser') ? rootProject['repoUser'] : 'cuba') + password(rootProject.hasProperty('repoPass') ? rootProject['repoPass'] : 'cuba123') + } + } + maven { + url "http://www.license4j.com/maven/" + } + } + dependencies { + classpath "com.haulmont.gradle:cuba-plugin:$cubaVersion" + } +} + +def modulePrefix = 'tms' + +def globalModule = project(":${modulePrefix}-global") +def coreModule = project(":${modulePrefix}-core") +def webModule = project(":${modulePrefix}-web") + +def servletApi = 'javax.servlet:javax.servlet-api:3.1.0' + +apply(plugin: 'cuba') + +cuba { + artifact { + group = 'com.cmobile.unifiedtms' + version = '0.5' + isSnapshot = false + } +} + +dependencies { + appComponent("com.haulmont.cuba:cuba-global:$cubaVersion") + appComponent('com.haulmont.addon.sdbmt:sdbmt-global:2.0.2') + appComponent('com.haulmont.addon.helium:helium-global:0.2.0') + appComponent('com.haulmont.addon.restapi:restapi-global:7.2.1') + appComponent('com.haulmont.addon.dashboard:dashboard-global:3.2.2') + appComponent("com.haulmont.charts:charts-global:$cubaVersion") + appComponent("com.haulmont.fts:fts-global:$cubaVersion") + appComponent('com.haulmont.addon.emailtemplates:yet-global:1.4.2') + appComponent('de.diedavids.cuba.dataimport:dataimport-global:0.14.1') + appComponent('com.cmobile.unifiedtms.ext:tmsext-global:0.2') + appComponent('ar.com.osmosys.pswdplus:pswdplus-global:1.1.0') +} + +def postgres = 'org.postgresql:postgresql:42.2.9' + +configure([globalModule, coreModule, webModule]) { + apply(plugin: 'java') + apply(plugin: 'maven') + apply(plugin: 'cuba') + + dependencies { + testCompile('org.junit.jupiter:junit-jupiter-api:5.5.2') + testCompile('org.junit.jupiter:junit-jupiter-engine:5.5.2') + testCompile('org.junit.vintage:junit-vintage-engine:5.5.2') + } + + task sourceJar(type: Jar) { + from file('src') + classifier = 'sources' + } + + artifacts { + archives sourceJar + } + test { + useJUnitPlatform() + } +} + + +configure(globalModule) { + dependencies { + if (!JavaVersion.current().isJava8()) { + runtime('javax.xml.bind:jaxb-api:2.3.1') + runtime('org.glassfish.jaxb:jaxb-runtime:2.3.1') + } + compileOnly(servletApi) + compile 'com.pras:apk-manifest:1.0' + compile 'com.license4j:license4j-runtime-library:4.7.3' + } + + entitiesEnhancing { + main { + enabled = true + } + } + + jar { + manifest { + attributes('App-Component-Id': cuba.artifact.group) + attributes('App-Component-Version': cuba.artifact.version + (cuba.artifact.isSnapshot ? '-SNAPSHOT' : '')) + } + } +} + +configure(coreModule) { + + configurations { + jdbc + dbscripts + } + + dependencies { + compile(globalModule) + compileOnly(servletApi) + jdbc(postgres) + testRuntime(postgres) + compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.4' + compile 'com.google.code.gson:gson:2.8.6' + compile 'com.pras:apk-manifest:1.0' + compile 'com.license4j:license4j-runtime-library:4.7.3' + runtime 'com.license4j:license4j-runtime-library:4.7.3' + compile 'commons-net:commons-net:3.8.0' + runtime 'commons-net:commons-net:3.8.0' + compile 'com.jcraft:jsch:0.1.55' + runtime 'com.jcraft:jsch:0.1.55' + } + + task cleanConf(description: 'Cleans up conf directory', type: Delete) { + delete "$cuba.appHome/${modulePrefix}-core/conf" + } + + task deploy(dependsOn: [assemble, cleanConf], type: CubaDeployment) { + appName = "${modulePrefix}-core" + appJars(modulePrefix + '-global', modulePrefix + '-core') + } + + task createDb(dependsOn: assembleDbScripts, description: 'Creates local database', type: CubaDbCreation) { + } + + task updateDb(dependsOn: assembleDbScripts, description: 'Updates local database', type: CubaDbUpdate) { + } +} + +configure(webModule) { + configurations { + webcontent + } + + dependencies { + compileOnly(servletApi) + compile(globalModule) + compile 'com.pras:apk-manifest:1.0' + compile 'com.license4j:license4j-runtime-library:4.7.3' + runtime 'com.license4j:license4j-runtime-library:4.7.3' + } + + + task webArchive(type: Zip) { + from file("$buildDir/web") + from file('web') + classifier = 'web' + } + + artifacts { + archives webArchive + } + + task deployConf(type: Copy) { + from file('src') + include "com/cmobile/unifiedtms/**" + into "$cuba.appHome/${modulePrefix}/conf" + } + + task clearMessagesCache(type: CubaClearMessagesCache) { + appName = "${modulePrefix}" + } + deployConf.dependsOn clearMessagesCache + + task cleanConf(description: 'Cleans up conf directory', type: Delete) { + delete "$cuba.appHome/${modulePrefix}/conf" + } + + task deploy(dependsOn: [assemble, cleanConf], type: CubaDeployment) { + appName = "${modulePrefix}" + appJars(modulePrefix + '-global', modulePrefix + '-web') + } + + task buildScssThemes(type: CubaWebScssThemeCreation) + + task deployThemes(type: CubaDeployThemeTask, dependsOn: buildScssThemes) + + assemble.dependsOn buildScssThemes + + task themesJar(type: Jar) { + from file('themes') + classifier = 'themes' + } + + artifacts { + archives themesJar + } +} + + +task undeploy(type: Delete, dependsOn: ":${modulePrefix}-web:cleanConf") { + delete("$cuba.tomcat.dir/shared") + delete("$cuba.tomcat.dir/webapps/${modulePrefix}-core") + delete("$cuba.tomcat.dir/webapps/${modulePrefix}") +} + +task restart(dependsOn: ['stop', ":${modulePrefix}-core:deploy", ":${modulePrefix}-web:deploy"], description: 'Redeploys applications and restarts local Tomcat') { + doLast { + ant.waitfor(maxwait: 6, maxwaitunit: 'second', checkevery: 2, checkeveryunit: 'second') { + not { + socket(server: 'localhost', port: '8787') + } + } + } +} +restart.finalizedBy start + +task buildWar(type: CubaWarBuilding) { + appProperties = ['cuba.automaticDatabaseUpdate': true] + includeJdbcDriver = true + logbackConfigurationFile = 'etc/war-logback.xml' + webXmlPath = 'modules/web/web/WEB-INF/single-war-web.xml' +} \ No newline at end of file diff --git a/etc/war-logback.xml b/etc/war-logback.xml new file mode 100644 index 0000000..d086e10 --- /dev/null +++ b/etc/war-logback.xml @@ -0,0 +1,166 @@ + + + + + + + + ${logDir}/app.log + + + DEBUG + + + + + ${logDir}/app.%d{yyyy-MM-dd}.log + + 30 + true + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread%X{cubaApp}%X{cubaUser}] %logger - %msg%n + + + + + + INFO + + + + %d{HH:mm:ss.SSS} %-5level %-40logger{36}- %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${logDir}/perfstat.log + true + + + ${logDir}/perfstat.%d{yyyy-MM-dd}.log + 30 + true + + + + %msg%n + + + + + + + + + + ${logDir}/perfstat-ui.log + true + + + ${logDir}/perfstat-ui.%d{yyyy-MM-dd}.log + 30 + true + + + + %msg%n + + + + + + + + + + + + + + + + + + + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..1948b9074f1016d15d505d185bc3f73deb82d8c8 GIT binary patch literal 54413 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/modules/core/db/init/postgres/01.ext-create-db.sql b/modules/core/db/init/postgres/01.ext-create-db.sql new file mode 100644 index 0000000..17384f2 --- /dev/null +++ b/modules/core/db/init/postgres/01.ext-create-db.sql @@ -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 diff --git a/modules/core/db/init/postgres/01.pswdplus-create-db.sql b/modules/core/db/init/postgres/01.pswdplus-create-db.sql new file mode 100644 index 0000000..9cc3e52 --- /dev/null +++ b/modules/core/db/init/postgres/01.pswdplus-create-db.sql @@ -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 diff --git a/modules/core/db/init/postgres/02.ext-create-db.sql b/modules/core/db/init/postgres/02.ext-create-db.sql new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/modules/core/db/init/postgres/02.ext-create-db.sql @@ -0,0 +1 @@ + diff --git a/modules/core/db/init/postgres/02.pswdplus-create-db.sql b/modules/core/db/init/postgres/02.pswdplus-create-db.sql new file mode 100644 index 0000000..a8e3f2f --- /dev/null +++ b/modules/core/db/init/postgres/02.pswdplus-create-db.sql @@ -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 diff --git a/modules/core/db/init/postgres/10.create-db.sql b/modules/core/db/init/postgres/10.create-db.sql new file mode 100644 index 0000000..0071a79 --- /dev/null +++ b/modules/core/db/init/postgres/10.create-db.sql @@ -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 diff --git a/modules/core/db/init/postgres/20.create-db.sql b/modules/core/db/init/postgres/20.create-db.sql new file mode 100644 index 0000000..f075bb1 --- /dev/null +++ b/modules/core/db/init/postgres/20.create-db.sql @@ -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 diff --git a/modules/core/db/init/postgres/30.create-db.sql b/modules/core/db/init/postgres/30.create-db.sql new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/modules/core/db/init/postgres/30.create-db.sql @@ -0,0 +1 @@ + diff --git a/modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink.sql b/modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink.sql new file mode 100644 index 0000000..dae4588 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink.sql @@ -0,0 +1 @@ +alter table tms_device_model_application_link rename to TMS_DEVICE_MODEL_APPLICATION_LINK__U48203 ; diff --git a/modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink_DropScript.sql b/modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink_DropScript.sql new file mode 100644 index 0000000..3179a4c --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-0-dropDeviceModelApplicationLink_DropScript.sql @@ -0,0 +1 @@ +drop table if exists TMS_DEVICE_MODEL_APPLICATION_LINK__U48203 cascade ; \ No newline at end of file diff --git a/modules/core/db/update/postgres/25/10/251002-1-updateDeleteTaskLog.sql b/modules/core/db/update/postgres/25/10/251002-1-updateDeleteTaskLog.sql new file mode 100644 index 0000000..d7fff01 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-1-updateDeleteTaskLog.sql @@ -0,0 +1 @@ +drop index IDX_TMS_DELETE_TASK_LOG_ON_TERMINAL ; diff --git a/modules/core/db/update/postgres/25/10/251002-1-updateDiagnosticInfo.sql b/modules/core/db/update/postgres/25/10/251002-1-updateDiagnosticInfo.sql new file mode 100644 index 0000000..0c070de --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-1-updateDiagnosticInfo.sql @@ -0,0 +1 @@ +drop index IDX_TMS_DIAGNOSTIC_INFO_ON_TERMINAL ; diff --git a/modules/core/db/update/postgres/25/10/251002-1-updateDownloadTaskLog.sql b/modules/core/db/update/postgres/25/10/251002-1-updateDownloadTaskLog.sql new file mode 100644 index 0000000..f53eb01 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-1-updateDownloadTaskLog.sql @@ -0,0 +1 @@ +drop index IDX_TMS_DOWNLOAD_TASK_LOG_ON_TERMINAL ; diff --git a/modules/core/db/update/postgres/25/10/251002-1-updateTerminalLink.sql b/modules/core/db/update/postgres/25/10/251002-1-updateTerminalLink.sql new file mode 100644 index 0000000..30bceb4 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-1-updateTerminalLink.sql @@ -0,0 +1 @@ +drop index IDX_TMS_TERMINAL_LINK_ON_TERMINAL ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateDeleteTaskLog01.sql b/modules/core/db/update/postgres/25/10/251002-2-updateDeleteTaskLog01.sql new file mode 100644 index 0000000..0bb8daa --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateDeleteTaskLog01.sql @@ -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); diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateDeviceProfileAcquirerLink.sql b/modules/core/db/update/postgres/25/10/251002-2-updateDeviceProfileAcquirerLink.sql new file mode 100644 index 0000000..5d675c9 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateDeviceProfileAcquirerLink.sql @@ -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 ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo.sql b/modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo.sql new file mode 100644 index 0000000..0552c65 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo.sql @@ -0,0 +1 @@ +alter table TMS_DIAGNOSTIC_INFO rename column device_info_ext to device_info_ext__u23585 ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo_DropScript.sql b/modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo_DropScript.sql new file mode 100644 index 0000000..e6641f7 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateDiagnosticInfo_DropScript.sql @@ -0,0 +1 @@ +alter table TMS_DIAGNOSTIC_INFO drop column DEVICE_INFO_EXT__U23585 cascade ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateDownloadTaskLog01.sql b/modules/core/db/update/postgres/25/10/251002-2-updateDownloadTaskLog01.sql new file mode 100644 index 0000000..236544d --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateDownloadTaskLog01.sql @@ -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); diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat.sql b/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat.sql new file mode 100644 index 0000000..a63dbd4 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat.sql @@ -0,0 +1,3 @@ +alter table TMS_HEART_BEAT rename column sn to sn__u07238 ; +-- update TMS_HEART_BEAT set TERMINAL_ID = where TERMINAL_ID is null ; +alter table TMS_HEART_BEAT alter column TERMINAL_ID set not null ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat01.sql b/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat01.sql new file mode 100644 index 0000000..dd2887c --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat01.sql @@ -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); diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat_DropScript.sql b/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat_DropScript.sql new file mode 100644 index 0000000..2ce0b02 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateHeartBeat_DropScript.sql @@ -0,0 +1 @@ +alter table TMS_HEART_BEAT drop column SN__U07238 cascade ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateTerminal.sql b/modules/core/db/update/postgres/25/10/251002-2-updateTerminal.sql new file mode 100644 index 0000000..07bcd2e --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateTerminal.sql @@ -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) ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateTerminalLink01.sql b/modules/core/db/update/postgres/25/10/251002-2-updateTerminalLink01.sql new file mode 100644 index 0000000..494846d --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateTerminalLink01.sql @@ -0,0 +1 @@ +alter table TMS_TERMINAL_LINK add constraint FK_TMS_TERMINAL_LINK_ON_TERMINAL foreign key (TERMINAL_ID) references TMS_TERMINAL(ID); diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateTerminal_DropScript.sql b/modules/core/db/update/postgres/25/10/251002-2-updateTerminal_DropScript.sql new file mode 100644 index 0000000..d4d6f85 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateTerminal_DropScript.sql @@ -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 ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt.sql b/modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt.sql new file mode 100644 index 0000000..1920f69 --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt.sql @@ -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 ; diff --git a/modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt_DropScript.sql b/modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt_DropScript.sql new file mode 100644 index 0000000..931bc2c --- /dev/null +++ b/modules/core/db/update/postgres/25/10/251002-2-updateTmsextTerminalExt_DropScript.sql @@ -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 ; diff --git a/modules/core/db/update/postgres/26/05/260511-1-createTerminalGroupImportStage.sql b/modules/core/db/update/postgres/26/05/260511-1-createTerminalGroupImportStage.sql new file mode 100644 index 0000000..0b01e28 --- /dev/null +++ b/modules/core/db/update/postgres/26/05/260511-1-createTerminalGroupImportStage.sql @@ -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); diff --git a/modules/core/db/update/postgres/26/05/260511-2-updateTerminalGroupImportStage.sql b/modules/core/db/update/postgres/26/05/260511-2-updateTerminalGroupImportStage.sql new file mode 100644 index 0000000..ea3b7ec --- /dev/null +++ b/modules/core/db/update/postgres/26/05/260511-2-updateTerminalGroupImportStage.sql @@ -0,0 +1 @@ +alter table TMS_TERMINAL_GROUP_IMPORT_STAGE add column if not exists SN_LOWER_NORM varchar(255); diff --git a/modules/core/src/com/cmobile/unifiedtms/MqttConfig.java b/modules/core/src/com/cmobile/unifiedtms/MqttConfig.java new file mode 100644 index 0000000..120d213 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/MqttConfig.java @@ -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(); + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/Singleton.java b/modules/core/src/com/cmobile/unifiedtms/Singleton.java new file mode 100644 index 0000000..2a7b8dc --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/Singleton.java @@ -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 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; + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/app.properties b/modules/core/src/com/cmobile/unifiedtms/app.properties new file mode 100644 index 0000000..56e4ca5 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/app.properties @@ -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 \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/config/LicenseConfig.java b/modules/core/src/com/cmobile/unifiedtms/config/LicenseConfig.java new file mode 100644 index 0000000..243e186 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/config/LicenseConfig.java @@ -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); +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/core/config/EchoTestConfig.java b/modules/core/src/com/cmobile/unifiedtms/core/config/EchoTestConfig.java new file mode 100644 index 0000000..1cc4139 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/config/EchoTestConfig.java @@ -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(); + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/config/ExtendedConfig.java b/modules/core/src/com/cmobile/unifiedtms/core/config/ExtendedConfig.java new file mode 100644 index 0000000..502a4b1 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/config/ExtendedConfig.java @@ -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(); + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/config/FileDownloadConfig.java b/modules/core/src/com/cmobile/unifiedtms/core/config/FileDownloadConfig.java new file mode 100644 index 0000000..1e63127 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/config/FileDownloadConfig.java @@ -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(); + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/config/TerminalUpdateConfig.java b/modules/core/src/com/cmobile/unifiedtms/core/config/TerminalUpdateConfig.java new file mode 100644 index 0000000..d58ef07 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/config/TerminalUpdateConfig.java @@ -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(); + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/BlindTrustManager.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/BlindTrustManager.java new file mode 100644 index 0000000..de6c3a2 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/BlindTrustManager.java @@ -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 { + + + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/MqttConnector.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/MqttConnector.java new file mode 100644 index 0000000..d830dbe --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/MqttConnector.java @@ -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 { + 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 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(); + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeleteTaskAckListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeleteTaskAckListener.java new file mode 100644 index 0000000..cec6dc6 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeleteTaskAckListener.java @@ -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 numbers = runner.query(query, + new ResultSetHandler>() { + @Nullable + @Override + public Set handle(ResultSet rs) throws SQLException { + Set rows = new HashSet(); + 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 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 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); + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeviceInitListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeviceInitListener.java new file mode 100644 index 0000000..920df22 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DeviceInitListener.java @@ -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 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); + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DiagnosticInfoListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DiagnosticInfoListener.java new file mode 100644 index 0000000..1ca2b3f --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DiagnosticInfoListener.java @@ -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> installedApps = (List>) map.get("installed_apps"); + if(installedApps != null) { + Metadata metadata = AppBeans.get(Metadata.NAME); + List 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 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); + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DownloadTaskAckListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DownloadTaskAckListener.java new file mode 100644 index 0000000..91add18 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/DownloadTaskAckListener.java @@ -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 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 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 numbers = runner.query(query, + new ResultSetHandler>() { + @Nullable + @Override + public Set handle(ResultSet rs) throws SQLException { + Set rows = new HashSet(); + 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); + } + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/EchoListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/EchoListener.java new file mode 100644 index 0000000..61762a4 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/EchoListener.java @@ -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; + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/HeartBeatListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/HeartBeatListener.java new file mode 100644 index 0000000..44c3c4b --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/HeartBeatListener.java @@ -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 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); + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/IncomingMessageListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/IncomingMessageListener.java new file mode 100644 index 0000000..4151467 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/IncomingMessageListener.java @@ -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); + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/PendingTaskPushListener.java b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/PendingTaskPushListener.java new file mode 100644 index 0000000..52df26b --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/mqtt/listener/PendingTaskPushListener.java @@ -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 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 deleteTaskLogs = getPendingDeleteTaskLogForTerminal(terminal); + List 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 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 getPendingDownloadTaskLogForTerminal(Terminal terminal) { + DataManager dataManager = AppBeans.get(DataManager.NAME); + LoadContext 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 getPendingDeleteTaskLogForTerminal(Terminal terminal) { + DataManager dataManager = AppBeans.get(DataManager.NAME); + LoadContext 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); + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/core/security/MyLoginEventListener.java b/modules/core/src/com/cmobile/unifiedtms/core/security/MyLoginEventListener.java new file mode 100644 index 0000000..5d4049e --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/security/MyLoginEventListener.java @@ -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()); + } + }); + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/core/security/UserSessionExistsAccessChecker.java b/modules/core/src/com/cmobile/unifiedtms/core/security/UserSessionExistsAccessChecker.java new file mode 100644 index 0000000..50da8d4 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/security/UserSessionExistsAccessChecker.java @@ -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; + } + +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/core/security/messages.properties b/modules/core/src/com/cmobile/unifiedtms/core/security/messages.properties new file mode 100644 index 0000000..c2f65aa --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/security/messages.properties @@ -0,0 +1 @@ +LoginException.concurrentUsersLimitExceeded = User already logged in!! \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/core/security/messages_in_ID.properties b/modules/core/src/com/cmobile/unifiedtms/core/security/messages_in_ID.properties new file mode 100644 index 0000000..619d931 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/core/security/messages_in_ID.properties @@ -0,0 +1 @@ +LoginException.concurrentUsersLimitExceeded = Pengguna sudah login!! \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/fts.xml b/modules/core/src/com/cmobile/unifiedtms/fts.xml new file mode 100644 index 0000000..d684ca6 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/fts.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/listeners/AppLifecycleEventListener.java b/modules/core/src/com/cmobile/unifiedtms/listeners/AppLifecycleEventListener.java new file mode 100644 index 0000000..2434b36 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/listeners/AppLifecycleEventListener.java @@ -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"); + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/APIServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/APIServiceBean.java new file mode 100644 index 0000000..c56488b --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/APIServiceBean.java @@ -0,0 +1,2821 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.MqttConfig; +import com.cmobile.unifiedtms.Singleton; +import com.cmobile.unifiedtms.core.config.TerminalUpdateConfig; +import com.cmobile.unifiedtms.entity.*; +import com.cmobile.unifiedtms.entity.enums.DownloadTimeType; +import com.cmobile.unifiedtms.entity.enums.InstallationTimeType; +import com.cmobile.unifiedtms.entity.enums.TaskNotificationType; +import com.cmobile.unifiedtms.entity.enums.TaskStatus; +import com.cmobile.unifiedtms.entity.misc.ExpirableObject; +import com.cmobile.unifiedtms.entity.misc.TerminalUpdateCacheObj; +import com.cmobile.unifiedtms.entity.restmodel.request.*; +import com.cmobile.unifiedtms.entity.restmodel.result.*; +import com.cmobile.unifiedtms.entity.restmodel.result.data.*; +import com.cmobile.unifiedtms.ext.entity.*; +import com.cmobile.unifiedtms.utils.ISOUtil; +import com.cmobile.unifiedtms.utils.TerminalUpdateCache; +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.app.FileStorageService; +import com.haulmont.cuba.core.app.UniqueNumbersAPI; +import com.haulmont.cuba.core.entity.FileDescriptor; +import com.haulmont.cuba.core.global.*; +import com.pras.Manifest; +import org.slf4j.Logger; +import org.springframework.stereotype.Service; +import sasc.iso7816.BERTLV; +import sasc.iso7816.TagImpl; +import sasc.iso7816.TagValueType; + +import javax.inject.Inject; +import java.io.ByteArrayOutputStream; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import javax.annotation.Nullable; + +@Service(APIService.NAME) +public class APIServiceBean implements APIService { + + @Inject + private UniqueNumbersAPI uniqueNumbersAPI; + @Inject + private Persistence persistence; + @Inject + private TenantProvider tenantProvider; + @Inject + private DataManager dataManager; + @Inject + private Messages messages; + @Inject + private Logger logger; + @Inject + private Metadata metadata; + @Inject + private FileStorageService fileStorageService; + @Inject + private ApkService apkService; + private SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyyMMdd"); + private SimpleDateFormat timestampDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private SimpleDateFormat fullTimestampDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + private SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm"); + @Inject + private TerminalUpdateConfig terminalUpdateConfig; + private TerminalUpdateCache terminalUpdateCache = new TerminalUpdateCache(); + @Inject + private MqttConfig mqttConfig; + // 24 hours cache + //private long expirationCache = TimeUnit.HOURS.toMillis(24); + // 5 minutes cache + private long expirationCache = TimeUnit.MINUTES.toMillis(5); + + @Override + public BasePaginatedResult listMerchant(PaginatedRequest req) { + BasePaginatedResult result = new BasePaginatedResult<>(); + try { + int pageNum = req.getPageNum(); + int totalPerPage = req.getTotalPerPage(); + + LoadContext loadContext = LoadContext.create(Merchant.class); + loadContext.setQueryString("select t from tms_Merchant t where t.deleteTs is null order by t.name"); + loadContext.getQuery().setMaxResults(totalPerPage); + loadContext.setView("merchant-minimal-view"); + + int totalCount = (int) dataManager.getCount(loadContext); + if (totalCount == 0) { + result.setTotal(0); + result.setTotalPage(0); + result.setRows(Collections.EMPTY_LIST); + } else { + int totalPage = pageSize(totalCount, totalPerPage); + int nextPageNo = 1; + if (pageNum != -1) { + nextPageNo = pageNum; + } + if (nextPageNo > totalPage) { + nextPageNo = totalPage; + } + if (nextPageNo <= 0) { + nextPageNo = 1; + } + int offset = (nextPageNo - 1) * totalPerPage; + result.setPageSize(totalPerPage); + loadContext.getQuery().setFirstResult(offset); + + List merchants = dataManager.loadList(loadContext); + List list = new ArrayList<>(); + merchants.forEach(merchant -> { + MerchantSimple _merchant = new MerchantSimple(); + _merchant.setId(merchant.getId()); + _merchant.setName(merchant.getName()); + _merchant.setCompanyName(merchant.getCompanyName()); + list.add(_merchant); + }); + + result.setTotal(totalCount); + result.setTotalPage(pageSize(totalCount, totalPerPage)); + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BasePaginatedResult listModel(PaginatedRequest req) { + BasePaginatedResult result = new BasePaginatedResult<>(); + try { + int pageNum = req.getPageNum(); + int totalPerPage = req.getTotalPerPage(); + + LoadContext loadContext = LoadContext.create(DeviceModel.class); + loadContext.setQueryString("select t from tms_DeviceModel t where t.deleteTs is null order by t.model"); + loadContext.getQuery().setMaxResults(totalPerPage); + loadContext.setView("deviceModel-minimal-view"); + + int totalCount = (int) dataManager.getCount(loadContext); + if (totalCount == 0) { + result.setTotal(0); + result.setTotalPage(0); + result.setRows(Collections.EMPTY_LIST); + } else { + int totalPage = pageSize(totalCount, totalPerPage); + int nextPageNo = 1; + if (pageNum != -1) { + nextPageNo = pageNum; + } + if (nextPageNo > totalPage) { + nextPageNo = totalPage; + } + if (nextPageNo <= 0) { + nextPageNo = 1; + } + int offset = (nextPageNo - 1) * totalPerPage; + result.setPageSize(totalPerPage); + loadContext.getQuery().setFirstResult(offset); + + List models = dataManager.loadList(loadContext); + List list = new ArrayList<>(); + models.forEach(deviceModel -> { + DeviceModelSimple model = new DeviceModelSimple(); + model.setId(deviceModel.getId()); + model.setModel(deviceModel.getModel()); + model.setVendorName(deviceModel.getVendorName()); + list.add(model); + }); + + result.setTotal(totalCount); + result.setTotalPage(pageSize(totalCount, totalPerPage)); + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult getModel(DetailRequest req) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + UUID id = req.getId(); + + LoadContext loadContext = LoadContext.create(DeviceModel.class); + loadContext.setQueryString("select t from tms_DeviceModel t where t.id = :id"); + loadContext.getQuery().setParameter("id", id); + loadContext.setView("deviceModel-view"); + + DeviceModel model = dataManager.load(loadContext); + if (model != null) { + DeviceModelDetail data = new DeviceModelDetail(); + data.setId(model.getId()); + data.setModel(model.getModel()); + data.setModelInformation(model.getModelInformation()); + data.setVendorName(model.getVendorName()); + data.setVendorCountry(model.getVendorCountry()); + + result.setData(data); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BasePaginatedResult listProfile(PaginatedRequest req) { + BasePaginatedResult result = new BasePaginatedResult<>(); + try { + int pageNum = req.getPageNum(); + int totalPerPage = req.getTotalPerPage(); + + LoadContext loadContext = LoadContext.create(DeviceProfile.class); + loadContext.setQueryString("select t from tms_DeviceProfile t where t.deleteTs is null order by t.name"); + loadContext.getQuery().setMaxResults(totalPerPage); + loadContext.setView("deviceProfile-minimal-view"); + + int totalCount = (int) dataManager.getCount(loadContext); + if (totalCount == 0) { + result.setTotal(0); + result.setTotalPage(0); + result.setRows(Collections.EMPTY_LIST); + } else { + int totalPage = pageSize(totalCount, totalPerPage); + int nextPageNo = 1; + if (pageNum != -1) { + nextPageNo = pageNum; + } + if (nextPageNo > totalPage) { + nextPageNo = totalPage; + } + if (nextPageNo <= 0) { + nextPageNo = 1; + } + int offset = (nextPageNo - 1) * totalPerPage; + result.setPageSize(totalPerPage); + loadContext.getQuery().setFirstResult(offset); + + List Profiles = dataManager.loadList(loadContext); + List list = new ArrayList<>(); + Profiles.forEach(deviceProfile -> { + DeviceProfileSimple Profile = new DeviceProfileSimple(); + Profile.setId(deviceProfile.getId()); + Profile.setName(deviceProfile.getName()); + Profile.setDefault(deviceProfile.getIsDefault()); + list.add(Profile); + }); + + result.setTotal(totalCount); + result.setTotalPage(pageSize(totalCount, totalPerPage)); + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult getProfile(DetailRequest req) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + UUID id = req.getId(); + + LoadContext loadContext = LoadContext.create(DeviceProfile.class); + loadContext.setQueryString("select t from tms_DeviceProfile t where t.id = :id"); + loadContext.getQuery().setParameter("id", id); + loadContext.setView("deviceProfile-view"); + + DeviceProfile Profile = dataManager.load(loadContext); + if (Profile != null) { + DeviceProfileDetail data = new DeviceProfileDetail(); + data.setId(Profile.getId()); + data.setName(Profile.getName()); + data.setHeartbeatInterval(Profile.getHeartbeatInterval()); + data.setDiagnosticInterval(Profile.getDiagnosticInterval()); + data.setMaskHomeButton(Profile.getMaskHomeButton()); + data.setMaskStatusBar(Profile.getMaskStatusBar()); + data.setScheduleReboot(Profile.getScheduleReboot()); + data.setScheduleRebootTime(Profile.getScheduleRebootTime()); + data.setRelocationAlert(Profile.getRelocationAlert()); + + result.setData(data); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BasePaginatedResult listTerminal(PaginatedRequest req) { + BasePaginatedResult result = new BasePaginatedResult<>(); + try { + int pageNum = req.getPageNum(); + int totalPerPage = req.getTotalPerPage(); + + LoadContext loadContext = LoadContext.create(Terminal.class); + loadContext.setQueryString("select t from tms_Terminal t where t.deleteTs is null order by t.sn"); + loadContext.getQuery().setMaxResults(totalPerPage); + loadContext.setView("terminal-minimal-view"); + + int totalCount = (int) dataManager.getCount(loadContext); + if (totalCount == 0) { + result.setTotal(0); + result.setTotalPage(0); + result.setRows(Collections.EMPTY_LIST); + } else { + int totalPage = pageSize(totalCount, totalPerPage); + int nextPageNo = 1; + if (pageNum != -1) { + nextPageNo = pageNum; + } + if (nextPageNo > totalPage) { + nextPageNo = totalPage; + } + if (nextPageNo <= 0) { + nextPageNo = 1; + } + int offset = (nextPageNo - 1) * totalPerPage; + result.setPageSize(totalPerPage); + loadContext.getQuery().setFirstResult(offset); + + List terminals = dataManager.loadList(loadContext); + List list = new ArrayList<>(); + terminals.forEach(terminal -> { + TerminalSimple _terminal = new TerminalSimple(); + _terminal.setId(terminal.getId()); + _terminal.setSn(terminal.getSn()); + _terminal.setImei(terminal.getImei()); + if(terminal.getModel() != null) { + _terminal.setModelName(terminal.getModel().getModel()); + } + if(terminal.getMerchant() != null) { + _terminal.setMerchantName(terminal.getMerchant().getName()); + } + if(terminal.getProfile() != null) { + _terminal.setProfileName(terminal.getProfile().getName()); + } + list.add(_terminal); + }); + + result.setTotal(totalCount); + result.setTotalPage(pageSize(totalCount, totalPerPage)); + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult getTerminal(TerminalDetailRequest req) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + String sn = req.getSn(); + + LoadContext loadContext = LoadContext.create(Terminal.class); + loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn) = :sn"); + loadContext.getQuery().setParameter("sn", sn.toLowerCase()); + loadContext.setView("terminal-view"); + + Terminal terminal = dataManager.load(loadContext); + if (terminal != null) { + TerminalDetail _terminal = new TerminalDetail(); + _terminal.setId(terminal.getId()); + _terminal.setSn(terminal.getSn()); + _terminal.setImei(terminal.getImei()); + if(terminal.getModel() != null) { + DeviceModelSimple model = new DeviceModelSimple(); + model.setId(terminal.getModel().getId()); + model.setModel(terminal.getModel().getModel()); + model.setVendorName(terminal.getModel().getVendorName()); + _terminal.setModel(model); + } + if(terminal.getMerchant() != null) { + MerchantSimple merchant = new MerchantSimple(); + merchant.setId(terminal.getMerchant().getId()); + merchant.setName(terminal.getMerchant().getName()); + _terminal.setMerchant(merchant); + } + if(terminal.getProfile() != null) { + DeviceProfileSimple profile = new DeviceProfileSimple(); + profile.setId(terminal.getProfile().getId()); + profile.setName(terminal.getProfile().getName()); + profile.setDefault(terminal.getProfile().getIsDefault()); + _terminal.setProfile(profile); + + // set acquirers to terminal ext + + } + + result.setData(_terminal); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult getTerminalExtAddress(TerminalDetailRequest req) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + String sn = req.getSn(); + + LoadContext loadContext = LoadContext.create(Terminal.class); + loadContext.setQueryString("select t from tms_Terminal t where lower(t.sn) = :sn"); + loadContext.getQuery().setParameter("sn", sn.toLowerCase()); + loadContext.setView("terminal-ext-address"); + + Terminal terminal = dataManager.load(loadContext); + if (terminal != null) { + TerminalLink terminalLink = terminal.getTerminalLink(); + if(terminalLink != null) { + TerminalExt terminalExt = terminalLink.getTerminalExt(); + + TerminalExtAddressSimple terminalExtAddressSimple = new TerminalExtAddressSimple(); + terminalExtAddressSimple.setId(terminalExt.getId()); + terminalExtAddressSimple.setSn(sn); + terminalExtAddressSimple.setTerminalId(terminalExt.getTerminalId()); + terminalExtAddressSimple.setMerchantId(terminalExt.getMerchantId()); + terminalExtAddressSimple.setMerchantName1(terminalExt.getMerchantName1()); + terminalExtAddressSimple.setMerchantName2(terminalExt.getMerchantName2()); + terminalExtAddressSimple.setMerchantName3(terminalExt.getMerchantName3()); + + result.setData(terminalExtAddressSimple); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0205"); + result.setResponseDesc("not-linked"); + } + + } else { + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult lastHeartbeat(String sn) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + LoadContext loadContext = LoadContext.create(TerminalLastHeartBeat.class); + loadContext.setQueryString("select t from tms_TerminalLastHeartBeat t where lower(t.terminalSn)=:sn"); + loadContext.setView("terminalLastHeartBeat-view"); + loadContext.getQuery().setParameter("sn", sn.toLowerCase()); + + TerminalLastHeartBeat lastHB = dataManager.load(loadContext); + if (lastHB == null) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + } else { + HearbeatSimple hb = new HearbeatSimple(); + hb.setTerminalSN(lastHB.getTerminalSn()); + hb.setBatteryPercentage(lastHB.getBatteryPercentage()); + hb.setBatteryTemp(lastHB.getBatteryTemp()); + hb.setLatitude(lastHB.getLatitude()); + hb.setLongitude(lastHB.getLongitude()); + hb.setUpdateTime(lastHB.getCreateTs()); + + result.setData(hb); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult lastDiagnostic(String sn) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + LoadContext loadContext = LoadContext.create(TerminalLastDiagnosticInfo.class); + loadContext.setQueryString("select t from tms_TerminalLastDiagnosticInfo t where lower(t.terminalSn)=:sn"); + loadContext.setView("terminalLastDiagnosticInfo-view"); + loadContext.getQuery().setParameter("sn", sn.toLowerCase()); + + TerminalLastDiagnosticInfo lastDiagnostic = dataManager.load(loadContext); + if (lastDiagnostic == null) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + } else { + // query installed apps + UUID id = lastDiagnostic.getId(); + LoadContext loadContextApp = LoadContext.create(ApplicationSimple.class); + loadContextApp.setQueryString("select t from tms_ApplicationSimple t where t.diagnosticInfo.id=:id"); + loadContextApp.setView("applicationSimple-view"); + loadContextApp.getQuery().setParameter("id", id); + List apps = dataManager.loadList(loadContextApp); + List installedApps = new ArrayList<>(); + apps.forEach(applicationSimple -> { + AppSimple app = new AppSimple(); + app.setAppName(applicationSimple.getAppName()); + app.setAppVersion(applicationSimple.getAppVersion()); + app.setPackageName(applicationSimple.getPackageName()); + installedApps.add(app); + }); + + DiagnosticSimple diagnostic = new DiagnosticSimple(); + diagnostic.setTerminalSN(lastDiagnostic.getTerminalSn()); + diagnostic.setBatteryPercentage(lastDiagnostic.getBatteryPercentage()); + diagnostic.setBatteryTemp(lastDiagnostic.getBatteryTemp()); + diagnostic.setLatitude(lastDiagnostic.getLatitude()); + diagnostic.setLongitude(lastDiagnostic.getLongitude()); + diagnostic.setMeid(lastDiagnostic.getMeid()); + diagnostic.setTotalMemory(lastDiagnostic.getTotalMemory()); + diagnostic.setAvailableMemory(lastDiagnostic.getAvailableMemory()); + diagnostic.setTotalFlashMemory(lastDiagnostic.getTotalFlashMemory()); + diagnostic.setAvailableFlashMemory(lastDiagnostic.getAvailableFlashMemory()); + diagnostic.setTotalMobileData(lastDiagnostic.getTotalMobileData()); + diagnostic.setSwitchingTimes(lastDiagnostic.getSwitchingTimes()); + diagnostic.setCurrentBootTime(lastDiagnostic.getCurrentBootTime()); + diagnostic.setTotalBootTime(lastDiagnostic.getTotalBootTime()); + diagnostic.setTotalLengthPrinted(lastDiagnostic.getTotalLengthPrinted()); + diagnostic.setSwipingCardTimes(lastDiagnostic.getSwipingCardTimes()); + diagnostic.setDipInsertingTimes(lastDiagnostic.getDipInsertingTimes()); + diagnostic.setNfcCardReadingTimes(lastDiagnostic.getNfcCardReadingTimes()); + diagnostic.setFrontCameraOpenTimes(lastDiagnostic.getFrontCameraOpenTimes()); + diagnostic.setRearCameraOpenTimes(lastDiagnostic.getRearCameraOpenTimes()); + diagnostic.setChargeTimes(lastDiagnostic.getChargeTimes()); + diagnostic.setInstalledApps(installedApps); + diagnostic.setUpdateTime(lastDiagnostic.getCreateTs()); + + result.setData(diagnostic); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseListResult listHeartbeat(String sn, Date startDate, Date endDate) { + BaseListResult result = new BaseListResult<>(); + try { + Calendar calStart = new GregorianCalendar(); + calStart.setTime(startDate); + calStart.set(Calendar.HOUR_OF_DAY, 0); + calStart.set(Calendar.MINUTE, 0); + calStart.set(Calendar.SECOND, 0); + calStart.set(Calendar.MILLISECOND, 0); + Calendar calEnd = new GregorianCalendar(); + calEnd.setTime(endDate); + calEnd.set(Calendar.HOUR_OF_DAY, 23); + calEnd.set(Calendar.MINUTE, 59); + calEnd.set(Calendar.SECOND, 59); + calEnd.set(Calendar.MILLISECOND, 999); + + long diffMs = calEnd.getTimeInMillis() - calStart.getTimeInMillis(); + long diffDays = diffMs / (24 * 60 * 60 * 1000); + if(diffDays > 7) { + result.setResponseCode("0403"); + result.setResponseDesc("Max period of 7 days."); + } else { + LoadContext loadContext = LoadContext.create(TerminalHeartBeat.class); + loadContext.setQueryString("select t from tms_TerminalHeartBeat t where t.terminalSn=:sn and t.createTs between :dateStart and :dateEnd"); + loadContext.setView("terminalHeartBeat-view"); + loadContext.getQuery().setParameter("sn", sn); + loadContext.getQuery().setParameter("dateStart", calStart.getTime()); + loadContext.getQuery().setParameter("dateEnd", calEnd.getTime()); + + List listHeartbeats = dataManager.loadList(loadContext); + if (listHeartbeats.isEmpty()) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + } else { + List list = new ArrayList<>(); + for (TerminalHeartBeat thb : listHeartbeats) { + HearbeatSimple hb = new HearbeatSimple(); + hb.setTerminalSN(thb.getTerminalSn()); + hb.setBatteryPercentage(thb.getBatteryPercentage()); + hb.setBatteryTemp(thb.getBatteryTemp()); + hb.setLatitude(thb.getLatitude()); + hb.setLongitude(thb.getLongitude()); + hb.setCellName(thb.getCellName()); + hb.setCellType(thb.getCellType()); + hb.setCellStrength(thb.getCellStrength()); + hb.setWifiName(thb.getWifiName()); + hb.setWifiStrength(thb.getWifiStrength()); + hb.setUpdateTime(thb.getCreateTs()); + list.add(hb); + } + + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseIdResult addTerminal(AddTerminalRequest req) { + BaseIdResult result = new BaseIdResult<>(); + try { + // validation + if(!validateAddTerminalRequest(req, result)) { + return result; + } + + // Device Profile + DeviceProfile profile = loadProfile(req.getProfileId()); + // Device Model + DeviceModel model = loadModel(req.getModelId()); + // Merchant + Merchant merchant = loadMerchant(req.getMerchantId()); + // Initial Groups + List groups = new ArrayList<>(); + if(req.getGroupIds() != null && !req.getGroupIds().isEmpty()) { + req.getGroupIds().forEach(groupId -> { + TerminalGroup group = new TerminalGroup(); + group.setId(groupId); + groups.add(group); + }); + } + + // new Terminal + Terminal terminal = metadata.create(Terminal.class); + terminal.setSn(req.getSn()); + terminal.setImei(req.getImei()); + terminal.setMerchant(merchant); + terminal.setProfile(profile); + terminal.setModel(model); + terminal.setGroup(groups); + + // Commit + terminal = dataManager.commit(terminal); + + if(terminal != null) { + result.setId(terminal.getId()); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0019"); + result.setResponseDesc("failure"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BasePaginatedResult listTerminalGroup(PaginatedRequest req) { + BasePaginatedResult result = new BasePaginatedResult<>(); + try { + int pageNum = req.getPageNum(); + int totalPerPage = req.getTotalPerPage(); + + LoadContext loadContext = LoadContext.create(TerminalGroup.class); + loadContext.setQueryString("select t from tms_TerminalGroup t where t.deleteTs is null order by t.name"); + loadContext.getQuery().setMaxResults(totalPerPage); + loadContext.setView("terminalGroup-view"); + + int totalCount = (int) dataManager.getCount(loadContext); + if (totalCount == 0) { + result.setTotal(0); + result.setTotalPage(0); + result.setRows(Collections.EMPTY_LIST); + } else { + int totalPage = pageSize(totalCount, totalPerPage); + int nextPageNo = 1; + if (pageNum != -1) { + nextPageNo = pageNum; + } + if (nextPageNo > totalPage) { + nextPageNo = totalPage; + } + if (nextPageNo <= 0) { + nextPageNo = 1; + } + int offset = (nextPageNo - 1) * totalPerPage; + result.setPageSize(totalPerPage); + loadContext.getQuery().setFirstResult(offset); + + List terminalGroups = dataManager.loadList(loadContext); + List list = new ArrayList<>(); + terminalGroups.forEach(_group -> { + TerminalGroupSimple group = new TerminalGroupSimple(); + group.setId(_group.getId()); + group.setName(_group.getName()); + group.setDescription(_group.getDescription()); + List _terminals = _group.getTerminals(); + _terminals.forEach(terminal -> { + group.getTerminals().add(terminal.getSn()); + }); + list.add(group); + }); + + result.setTotal(totalCount); + result.setTotalPage(pageSize(totalCount, totalPerPage)); + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseIdResult addTerminalGroup(AddTerminalGroupRequest req) { + BaseIdResult result = new BaseIdResult<>(); + try { + // validation + if(!validateAddTerminalGroupRequest(req, result)) { + return result; + } + + // new Terminal Group + TerminalGroup terminalGroup = metadata.create(TerminalGroup.class); + terminalGroup.setName(req.getName()); + terminalGroup.setDescription(req.getDescription()); + + List terminals = new ArrayList<>(); + if(req.getTerminals() != null && !req.getTerminals().isEmpty()) { + req.getTerminals().forEach(_terminalSN -> { + Terminal terminal = loadTerminalBySN(_terminalSN); + if(terminal != null) { + terminals.add(terminal); + } else { + throw new RuntimeException("Invalid Terminal: " + _terminalSN); + } + }); + } + terminalGroup.setTerminals(terminals); + + // Commit + terminalGroup = dataManager.commit(terminalGroup); + + if(terminalGroup != null) { + result.setId(terminalGroup.getId()); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0019"); + result.setResponseDesc("failure"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseResult editTerminalGroup(EditTerminalGroupRequest req) { + BaseResult result = new BaseResult(); + try { + // validation + if(!validateEditTerminalGroupRequest(req, result)) { + return result; + } + + // new Terminal Group + TerminalGroup terminalGroup = loadTerminalGroup(req.getId()); + if(terminalGroup == null) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + return result; + } + terminalGroup.setName(req.getName()); + terminalGroup.setDescription(req.getDescription()); + + List terminals = new ArrayList<>(); + if(req.getTerminals() != null && !req.getTerminals().isEmpty()) { + req.getTerminals().forEach(_terminalSN -> { + Terminal terminal = loadTerminalBySN(_terminalSN); + if(terminal != null) { + terminals.add(terminal); + } else { + throw new RuntimeException("Invalid Terminal: " + _terminalSN); + } + }); + } + if(!terminals.isEmpty()) { + terminalGroup.setTerminals(terminals); + } + + // Commit + terminalGroup = dataManager.commit(terminalGroup); + + if(terminalGroup != null) { + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0019"); + result.setResponseDesc("failure"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseResult deleteTerminalGroup(DeleteRequest req) { + BaseResult result = new BaseResult(); + try { + // new Terminal Group + TerminalGroup terminalGroup = loadTerminalGroup(req.getId()); + if(terminalGroup == null) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + return result; + } + + // Commit + dataManager.remove(terminalGroup); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseResult addTerminalToGroup(TerminalAssignRequest req) { + BaseResult result = new BaseResult(); + try { + // validation + if(!validateTerminalAssignRequest(req, result)) { + return result; + } + + // new Terminal Group + TerminalGroup terminalGroup = loadTerminalGroup(req.getGroupId()); + if(terminalGroup == null) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + return result; + } + List terminals = terminalGroup.getTerminals(); + boolean contained = false; + for(Terminal terminal : terminals) { + contained = terminal.getSn().equalsIgnoreCase(req.getSn()); + if(contained) break; + } + if(contained) { + result.setResponseCode("0199"); + result.setResponseDesc("already-exists"); + return result; + } + Terminal terminal = loadTerminalBySN(req.getSn()); + if(terminal == null) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + return result; + } + terminals.add(terminal); + terminalGroup.setTerminals(terminals); + + // Commit + terminalGroup = dataManager.commit(terminalGroup); + + if(terminalGroup != null) { + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0019"); + result.setResponseDesc("failure"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseResult removeTerminalFromGroup(TerminalAssignRequest req) { + BaseResult result = new BaseResult(); + try { + // validation + if(!validateTerminalAssignRequest(req, result)) { + return result; + } + + // new Terminal Group + TerminalGroup terminalGroup = loadTerminalGroup(req.getGroupId()); + if(terminalGroup == null) { + result.setResponseCode("0404"); + result.setResponseDesc("not-found"); + return result; + } + List terminals = terminalGroup.getTerminals(); + boolean contained = false; + for(Terminal terminal : terminals) { + contained = terminal.getSn().equalsIgnoreCase(req.getSn()); + if(contained) break; + } + if(!contained) { + result.setResponseCode("0198"); + result.setResponseDesc("not-contained"); + return result; + } + Terminal terminal = loadTerminalBySN(req.getSn()); + List newTerminals = new ArrayList<>(); + for(Terminal _terminal : terminals) { + if(!_terminal.getSn().equalsIgnoreCase(req.getSn())) { + newTerminals.add(_terminal); + } + } + terminalGroup.setTerminals(newTerminals); + + // Commit + terminalGroup = dataManager.commit(terminalGroup); + + if(terminalGroup != null) { + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0019"); + result.setResponseDesc("failure"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseIdResult addApplication(AddApplicationRequest req) { + BaseIdResult result = new BaseIdResult<>(); + try { + // validation + if(!validateAddApplicationRequest(req, result)) { + return result; + } + + // apk file + FileDescriptor apkFileDescriptor = loadFileDescriptor(req.getApkFileId()); + FileDescriptor iconFileDescriptor = req.getIconFileId() != null ? loadFileDescriptor(req.getIconFileId()) : null; + if(apkFileDescriptor == null) { + result.setResponseCode("0203"); + result.setResponseDesc("file-not-found"); + return result; + } + + // extract manifest from apk file + byte[] bytes = fileStorageService.loadFile(apkFileDescriptor); + Manifest manifest = apkService.extractManifest(bytes); + if(manifest == null) { + result.setResponseCode("0204"); + result.setResponseDesc("invalid-file"); + return result; + } + + // new Application + Application application = metadata.create(Application.class); + application.setPackageName(manifest.getPackage()); + application.setName(req.getName()); + application.setCompanyName(req.getCompanyName()); + application.setDescription(req.getDescription()); + application.setAppVersion(manifest.getVersionName()); + application.setUninstallable(req.getUninstallable()); + application.setApk(apkFileDescriptor); + application.setIcon(iconFileDescriptor); + + // Commit + application = dataManager.commit(application); + + if(application != null) { + result.setId(application.getId()); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0019"); + result.setResponseDesc("failure"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseIdResult addDownloadTask(AddDownloadTaskRequest req) { + BaseIdResult result = new BaseIdResult<>(); + try { + // validation + if(!validateAddDownloadTaskRequest(req, result)) { + return result; + } + + DownloadTimeType downloadTimeType = DownloadTimeType.fromId(req.getDownloadTimeType()); + InstallationTimeType installationTimeType = InstallationTimeType.fromId(req.getInstallationTimeType()); + TaskNotificationType installationNotificationType = TaskNotificationType.fromId(req.getInstallationNotification()); + List applications = new ArrayList<>(); + List groups = new ArrayList<>(); + req.getTerminalGroupIds().forEach(uuid -> { + TerminalGroup terminalGroup = loadTerminalGroup(uuid); + if(terminalGroup == null) { + throw new RuntimeException("Invalid Terminal Group: " + uuid); + } + groups.add(terminalGroup); + }); + req.getApplicationIds().forEach(uuid -> { + Application application = loadApplication(uuid); + if(application == null) { + throw new RuntimeException("Invalid Application: " + uuid); + } + applications.add(application); + }); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + sdf.setLenient(false); + + // create new task + DownloadTask downloadTask = metadata.create(DownloadTask.class); + downloadTask.setName(req.getName()); + downloadTask.setStatus(TaskStatus.NOT_STARTED); + downloadTask.setDownloadTimeType(downloadTimeType); + if(downloadTimeType == DownloadTimeType.DATETIME) { + downloadTask.setDownloadTime(sdf.parse(req.getDownloadTime())); + } + downloadTask.setInstallationTimeType(installationTimeType); + if(installationTimeType == InstallationTimeType.DATETIME) { + downloadTask.setInstallationTime(sdf.parse(req.getInstallationTime())); + } + downloadTask.setInstallationNotification(installationNotificationType); + downloadTask.setApplications(applications); + downloadTask.setTerminalGroups(groups); + + // Commit + downloadTask = dataManager.commit(downloadTask); + + if(downloadTask != null) { + result.setId(downloadTask.getId()); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0019"); + result.setResponseDesc("failure"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BasePaginatedResult listDownloadTask(PaginatedRequest req) { + BasePaginatedResult result = new BasePaginatedResult<>(); + try { + int pageNum = req.getPageNum(); + int totalPerPage = req.getTotalPerPage(); + + LoadContext loadContext = LoadContext.create(DownloadTask.class); + loadContext.setQueryString("select t from tms_DownloadTask t where t.deleteTs is null order by t.name"); + loadContext.getQuery().setMaxResults(totalPerPage); + loadContext.setView("downloadTask-minimal-view"); + + int totalCount = (int) dataManager.getCount(loadContext); + if (totalCount == 0) { + result.setTotal(0); + result.setTotalPage(0); + result.setRows(Collections.EMPTY_LIST); + } else { + int totalPage = pageSize(totalCount, totalPerPage); + int nextPageNo = 1; + if (pageNum != -1) { + nextPageNo = pageNum; + } + if (nextPageNo > totalPage) { + nextPageNo = totalPage; + } + if (nextPageNo <= 0) { + nextPageNo = 1; + } + int offset = (nextPageNo - 1) * totalPerPage; + result.setPageSize(totalPerPage); + loadContext.getQuery().setFirstResult(offset); + + List tasks = dataManager.loadList(loadContext); + List list = new ArrayList<>(); + tasks.forEach(task -> { + DownloadTaskSimple model = new DownloadTaskSimple(); + model.setId(task.getId()); + model.setName(task.getName()); + model.setStatus(task.getStatus().getId()); + list.add(model); + }); + + result.setTotal(totalCount); + result.setTotalPage(pageSize(totalCount, totalPerPage)); + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } + } catch(Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult getDownloadTask(DetailRequest req) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + UUID id = req.getId(); + + LoadContext loadContext = LoadContext.create(DownloadTask.class); + loadContext.setQueryString("select t from tms_DownloadTask t where t.id = :id and t.deleteTs is null"); + loadContext.getQuery().setParameter("id", id); + loadContext.setView("downloadTask-view"); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + DownloadTask task = dataManager.load(loadContext); + if (task != null) { + DownloadTaskDetail data = new DownloadTaskDetail(); + data.setId(task.getId()); + data.setName(task.getName()); + data.setDownloadTimeType(task.getDownloadTimeType().getId()); + if(task.getDownloadTimeType() == DownloadTimeType.DATETIME) { + data.setDownloadTime(sdf.format(task.getDownloadTime())); + } + data.setInstallationTimeType(task.getInstallationTimeType().getId()); + if(task.getInstallationTimeType() == InstallationTimeType.DATETIME) { + data.setInstallationTime(sdf.format(task.getInstallationTime())); + } + data.setInstallationNotification(task.getInstallationNotification().getId()); + if(task.getApplications() != null && !task.getApplications().isEmpty()) { + task.getApplications().forEach(application -> { + data.getApplicationIds().add(application.getId()); + }); + } + if(task.getTerminalGroups() != null && !task.getTerminalGroups().isEmpty()) { + task.getTerminalGroups().forEach(terminalGroup -> { + data.getTerminalGroupIds().add(terminalGroup.getId()); + }); + } + data.setStatus(task.getStatus().getId()); + + result.setData(data); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public Map init(InitProfileRequest req) { + long start = System.currentTimeMillis(); + logger.info("Request INIT Start: {}", req.getSn()); + Map messageMap = new HashMap(); + messageMap.put("req_id", UUID.randomUUID().toString()); + messageMap.put("req_time", timestampDateFormat.format(new Date())); + messageMap.put("req_type", "UPDATE_PARAM"); + + String terminalSource = "db"; + String profileSource = "db"; + try { + Map> terminalCache = (Map) Singleton.getInstance("terminal-cache").getObject(); + if(terminalCache == null) { + terminalCache = new HashMap<>(); + Singleton.getInstance("terminal-cache").setObject(terminalCache); + } + Map> profileCache = (Map) Singleton.getInstance("profile-cache").getObject(); + if(profileCache == null) { + profileCache = new HashMap<>(); + Singleton.getInstance("profile-cache").setObject(profileCache); + } + ExpirableObject terminalObj = terminalCache.get(req.getSn()); + //logger.info(">> terminalObj: {}", terminalObj); + Terminal terminal = terminalObj != null ? terminalObj.getObject() : null; + Map profileMap = null; + if(terminal != null) { + terminalSource = "cache"; + ExpirableObject profileObj = profileCache.get(terminal.getProfile().getId()); + //logger.info(">> profileObj (1): {}", profileObj); + profileMap = profileObj != null ? profileObj.getObject() : null; + } + + if(terminal == null && profileMap == null) { + //logger.info("loadTerminalMinimalBySN: {}", req.getSn()); + terminal = loadTerminalMinimalBySN(req.getSn()); + if(terminal != null) { + terminalCache.put(req.getSn(), new ExpirableObject(terminal, expirationCache)); + if(terminal.getProfile() != null) { + ExpirableObject profileObj = profileCache.get(terminal.getProfile().getId()); + //logger.info(">> profileObj (2): {}", profileObj); + profileMap = profileObj != null ? profileObj.getObject() : null; + if(profileMap != null) { + profileSource = "cache"; + } + } + } + } else if(terminal == null && profileMap != null) { + //logger.info("profileMap exists, loadTerminalMinimalOnlyProfileIdBySN: {}", req.getSn()); + // only profile id + terminal = loadTerminalMinimalOnlyProfileIdBySN(req.getSn()); + terminalCache.put(req.getSn(), new ExpirableObject(terminal, expirationCache)); + } + + //logger.info(">> Terminal NOT NULL? {}", terminal != null); + //logger.info(">> Profile NOT NULL? {}", profileMap != null); + // load from database + if(terminal != null) { + if (profileMap == null) { + DeviceProfile profile = terminal.getProfile(); + if(profile != null) { + //logger.info("contruct and cache profile: {}", profile.getId()); + + // profile map + profileMap = new HashMap<>(); + profileMap.put("id", profile.getId()); + profileMap.put("name", profile.getName()); + profileMap.put("hearbeat_interval", profile.getHeartbeatInterval()); + profileMap.put("diagnostic_interval", profile.getDiagnosticInterval()); + profileMap.put("mask_home_button", normalizeBoolean(profile.getMaskHomeButton())); + profileMap.put("mask_status_button", normalizeBoolean(profile.getMaskStatusBar())); + profileMap.put("schedule_reboot", normalizeBoolean(profile.getScheduleReboot())); + if (profile.getScheduleReboot()) { + profileMap.put("schedule_reboot_time", timeFormat.format(profile.getScheduleRebootTime())); + } + profileMap.put("relocation_alert", normalizeBoolean(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 apps = profile.getApps(); + List appList = new ArrayList<>(); + for (DeviceProfileApp app : apps) { + appList.add(app.getPackageName()); + } + profileMap.put("apps_home_list", appList); + // hardcoded auto reconnect + profileMap.put("auto_reconnect", true); + + List groups = terminal.getGroup(); + List groupIds = new ArrayList<>(); + for (TerminalGroup group : groups) { + groupIds.add(group.getId()); + } + profileMap.put("group_list", groupIds); + + messageMap.put("profile", profileMap); + profileCache.put(profile.getId(), new ExpirableObject(profileMap, expirationCache)); + //logger.info("Taken from db!"); + } else { + logger.error("Terminal having no profile: {}", req.getSn()); + } + } else { + List groups = terminal.getGroup(); + List groupIds = new ArrayList<>(); + for (TerminalGroup group : groups) { + groupIds.add(group.getId()); + } + profileMap.put("group_list", groupIds); + + //logger.info("Taken from cache!"); + messageMap.put("profile", profileMap); + profileSource = "cache"; + } + } else { + // invalid sn + logger.error("Invalid SN: {}", req.getSn()); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + } + logger.info("Terminal : {}, Profile: {}", terminalSource, profileSource); + long end = System.currentTimeMillis(); + logger.info("Request INIT Done: {} in {} ms", req.getSn(), (end-start)); + return messageMap; + } + + @Override + public BaseListExtResult initAidList(InitProfileRequest req) { + BaseListExtResult result = new BaseListExtResult<>(); + try { + List aidStringList = null;//(List) Singleton.getInstance("aid-list").getObject(); + if(aidStringList == null) { + LoadContext loadContext = LoadContext.create(Aid.class); + loadContext.setQueryString("select t from tms$Aid t where t.deleteTs is null"); + loadContext.setView("aid-view"); + List list = dataManager.loadList(loadContext); + aidStringList = new ArrayList<>(); + for(Aid aid : list) { + try { + aidStringList.add(buildAid(aid)); + } catch (Exception ex) { + logger.error("Error Build AID: {}", aid); + } + }; + Singleton.getInstance("aid-list").setObject(aidStringList); + } + result.setRows(aidStringList); + // hardcoded + UpdateAidData updateAidData = new UpdateAidData(); + updateAidData.setUpdateAid(false); + result.setData(updateAidData); + result.setInitTime(new Date()); + + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + TerminalLastStepUpdate terminalLastStepUpdate = metadata.create(TerminalLastStepUpdate.class); + terminalLastStepUpdate.setStepName("AID"); + terminalLastStepUpdate.setSn(req.getSn()); + terminalLastStepUpdate.setLastInitTime(lastInitTime); + dataManager.commit(terminalLastStepUpdate); + + // update cache status + TerminalUpdateCacheObj cacheObj = terminalUpdateCache.get(req.getSn()); + if(cacheObj != null) { + cacheObj.continueStep("AID"); + if ("Finished".equalsIgnoreCase(cacheObj.getStatus())) { + terminalUpdateCache.updateToFinished(req.getSn(), cacheObj); + } + } + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseListExtResult initCtlsAidList(InitProfileRequest req) { + BaseListExtResult result = new BaseListExtResult<>(); + try { + List aidStringList = null;//(List) Singleton.getInstance("ctls-aid-list").getObject(); + if(aidStringList == null) { + LoadContext loadContext = LoadContext.create(Aid.class); + loadContext.setQueryString("select t from tms$Aid t where t.deleteTs is null"); + loadContext.setView("aid-view"); + List list = dataManager.loadList(loadContext); + aidStringList = new ArrayList<>(); + for(Aid aid : list) { + try { + aidStringList.add(buildContactlessAid(aid)); + } catch (Exception ex) { + logger.error("Error Build AID: {}", aid); + } + }; + Singleton.getInstance("ctls-aid-list").setObject(aidStringList); + } + result.setRows(aidStringList); + // hardcoded + UpdateContactlessAidData updateContactlessAidData = new UpdateContactlessAidData(); + updateContactlessAidData.setUpdateCtlsAid(false); + result.setData(updateContactlessAidData); + result.setInitTime(new Date()); + + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + TerminalLastStepUpdate terminalLastStepUpdate = metadata.create(TerminalLastStepUpdate.class); + terminalLastStepUpdate.setStepName("Contactless AID"); + terminalLastStepUpdate.setSn(req.getSn()); + terminalLastStepUpdate.setLastInitTime(lastInitTime); + dataManager.commit(terminalLastStepUpdate); + + // update cache status + TerminalUpdateCacheObj cacheObj = terminalUpdateCache.get(req.getSn()); + if(cacheObj != null) { + cacheObj.continueStep("Contactless AID"); + if ("Finished".equalsIgnoreCase(cacheObj.getStatus())) { + terminalUpdateCache.updateToFinished(req.getSn(), cacheObj); + } + } + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseListExtResult initCapkList(InitProfileRequest req) { + BaseListExtResult result = new BaseListExtResult<>(); + try { + List capkStringList = null;//(List) Singleton.getInstance("capk-list").getObject(); + if(capkStringList == null) { + capkStringList = new ArrayList<>(); + LoadContext loadContext = LoadContext.create(Capk.class); + loadContext.setQueryString("select t from tms$Capk t where t.deleteTs is null"); + loadContext.setView("capk-view"); + List list = dataManager.loadList(loadContext); + for(Capk capk : list) { + try { + capkStringList.add(buildCapk(capk)); + } catch (Exception ex) { + logger.error("Error Build CAPK: {}", capk); + } + }; + Singleton.getInstance("capk-list").setObject(capkStringList); + } + result.setRows(capkStringList); + + + // hardcoded + UpdateCapkData updateCapkData = new UpdateCapkData(); + updateCapkData.setUpdateCapk(false); + result.setData(updateCapkData); + result.setInitTime(new Date()); + + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + TerminalLastStepUpdate terminalLastStepUpdate = metadata.create(TerminalLastStepUpdate.class); + terminalLastStepUpdate.setStepName("CAPK"); + terminalLastStepUpdate.setSn(req.getSn()); + terminalLastStepUpdate.setLastInitTime(lastInitTime); + dataManager.commit(terminalLastStepUpdate); + + // update cache status + TerminalUpdateCacheObj cacheObj = terminalUpdateCache.get(req.getSn()); + if(cacheObj != null) { + cacheObj.continueStep("CAPK"); + if ("Finished".equalsIgnoreCase(cacheObj.getStatus())) { + terminalUpdateCache.updateToFinished(req.getSn(), cacheObj); + } + } + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseListExtResult initCardList(InitProfileRequest req) { + BaseListExtResult result = new BaseListExtResult<>(); + try { + Object[] terminals = loadTerminalsExtBySN(req.getSn(), "terminal-with-profile-view", "terminalLink-with-profile-view"); + TerminalExt terminalExt = (TerminalExt) terminals[1]; + Terminal terminal = (Terminal) terminals[0]; + if(terminal != null && terminal.getProfile() != null) { + List acquirers = terminal.getProfile().getAcquirers(); + List cards = new ArrayList<>(); + for(Acquirer acquirer : acquirers) { + acquirer.getIssuers().forEach(issuer -> { + issuer.getCards().forEach(card -> { + card.setIssuerId(issuer.getId().toString()); + card.setAcquirerId(issuer.getAcquirer().getId().toString()); + + cards.add(card); + }); + }); + } + result.setRows(cards); + // hardcoded + UpdateCardData updateCardData = new UpdateCardData(); + updateCardData.setUpdateCard(false); + result.setData(updateCardData); + result.setInitTime(new Date()); + + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + TerminalLastStepUpdate terminalLastStepUpdate = metadata.create(TerminalLastStepUpdate.class); + terminalLastStepUpdate.setStepName("Cards"); + terminalLastStepUpdate.setSn(req.getSn()); + terminalLastStepUpdate.setLastInitTime(lastInitTime); + dataManager.commit(terminalLastStepUpdate); + + // update cache status + TerminalUpdateCacheObj cacheObj = terminalUpdateCache.get(req.getSn()); + if(cacheObj != null) { + cacheObj.continueStep("Cards"); + if ("Finished".equalsIgnoreCase(cacheObj.getStatus())) { + terminalUpdateCache.updateToFinished(req.getSn(), cacheObj); + } + } + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + logger.warn("Terminal Ext Not Found: {}", req.getSn()); + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailExtResult initTerminal(InitProfileRequest req) { + BaseDetailExtResult result = new BaseDetailExtResult<>(); + try { + Object[] terminals = loadTerminalsExtBySN(req.getSn(), "terminal-view", "terminalLink-with-profile-view"); + TerminalExt terminalExt = (TerminalExt) terminals[1]; + Terminal terminal = (Terminal) terminals[0]; + //logger.error("[1] Terminal Ext: {}", terminalExt); + if(terminalExt != null) { + LoadContext loadContext = LoadContext.create(TerminalExt.class); + loadContext.setQueryString("select t from tms$TerminalExt t where t.id=:id and t.deleteTs is null"); + loadContext.getQuery().setParameter("id", terminalExt.getId()); + loadContext.setView("terminalExt-rest-view"); + terminalExt = dataManager.load(loadContext); + //logger.error("[2] Terminal Ext: {}", terminalExt); + //logger.error("[3] Profile Host Report: {}", terminal.getProfile().getHostReport()); + //logger.error("[3] Profile Host Report API Key: {}", terminal.getProfile().getHostReportApiKey()); + //logger.error("[3] Profile Host Report URL: {}", terminal.getProfile().getHostReportUrl()); + //logger.error("[3] Profile Host Report Timeout: {}", terminal.getProfile().getHostReportTimeout()); + //logger.error("[4] Profile Host Logging: {}", terminal.getProfile().getHostLogging()); + //logger.error("[4] Profile Host Logging API Key: {}", terminal.getProfile().getHostLoggingApiKey()); + //logger.error("[4] Profile Host Logging URL: {}", terminal.getProfile().getHostLoggingUrl()); + //logger.error("[4] Profile Host Logging Timeout: {}", terminal.getProfile().getHostLoggingTimeout()); + //logger.error("[4] Auto Start App: {}", terminal.getProfile().getAutoStartApp()); + //logger.error("[4] Skip Password: {}", terminalExt.getSkipPassword()); + + // set terminal ext acquirers from profile + if(terminalExt != null) { + if (terminal.getProfile() != null) { + terminalExt.setAcquirers(terminal.getProfile().getAcquirers()); + if (terminalExt.getAcquirers() != null) { + for (Acquirer acquirer : terminalExt.getAcquirers()) { + // set tid & mid from terminal ext + acquirer.setTerminalID(terminalExt.getTerminalId()); + acquirer.setMerchantID(terminalExt.getMerchantId()); + } + } + // if not set in terminal, use from profile + if(terminalExt.getHostReport() == null) { + terminalExt.setHostReport(terminal.getProfile().getHostReport()); + } + terminalExt.setHostReportApiKey(terminal.getProfile().getHostReportApiKey()); + terminalExt.setHostReportUrl(terminal.getProfile().getHostReportUrl()); + terminalExt.setHostReportTimeout(terminal.getProfile().getHostReportTimeout()); + // if not set in terminal, use from profile + if(terminalExt.getHostLogging() == null) { + terminalExt.setHostLogging(terminal.getProfile().getHostLogging()); + } + terminalExt.setHostLoggingApiKey(terminal.getProfile().getHostLoggingApiKey()); + terminalExt.setHostLoggingUrl(terminal.getProfile().getHostLoggingUrl()); + terminalExt.setHostLoggingTimeout(terminal.getProfile().getHostLoggingTimeout()); + if(terminalExt.getSkipPassword() == null) { + terminalExt.setSkipPassword(false); + } + + terminalExt.setAutoStartApp(terminal.getProfile().getAutoStartApp() != null ? + terminal.getProfile().getAutoStartApp() : false); + } + } + + result.setData(terminalExt); + // hardcoded + UpdateTerminalData updateTerminalData = new UpdateTerminalData(); + updateTerminalData.setUpdateTerminal(false); + updateTerminalData.setKeepBatch(true); + + // response codes + LoadContext rcLoadContext = LoadContext.create(ResponseCode.class); + rcLoadContext.setQueryString("select t from tms_ResponseCode t where t.deleteTs is null order by t.type, t.code"); + rcLoadContext.setView("responseCode-view"); + List rcList = dataManager.loadList(rcLoadContext); + List rcSimpleList = new ArrayList<>(); + rcList.forEach(rc -> { + ResponseCodeSimple simple = new ResponseCodeSimple(); + simple.setType(rc.getType().name()); + simple.setCode(rc.getCode()); + simple.setDesc(rc.getDesc()); + rcSimpleList.add(simple); + }); + updateTerminalData.setResponseCodes(rcSimpleList); + + result.setDataExt(updateTerminalData); + result.setInitTime(new Date()); + + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + TerminalLastStepUpdate terminalLastStepUpdate = metadata.create(TerminalLastStepUpdate.class); + terminalLastStepUpdate.setStepName("Terminal"); + terminalLastStepUpdate.setSn(req.getSn()); + terminalLastStepUpdate.setLastInitTime(lastInitTime); + dataManager.commit(terminalLastStepUpdate); + + // update cache status + TerminalUpdateCacheObj cacheObj = terminalUpdateCache.get(req.getSn()); + if(cacheObj != null) { + cacheObj.continueStep("Terminal"); + if ("Finished".equalsIgnoreCase(cacheObj.getStatus())) { + terminalUpdateCache.updateToFinished(req.getSn(), cacheObj); + } + } + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + logger.warn("Terminal Ext Not Found: {}", req.getSn()); + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailExtResult checkParameterUpdate(CheckUpdateRequest req) { + BaseDetailExtResult result = new BaseDetailExtResult<>(); + try { + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + + UpdateTerminalData updateTerminalData = new UpdateTerminalData(); + boolean forceUpdate = false; + String updateMode = terminalUpdateConfig.getForceNotUpdateMode(); + + boolean terminalHasUpdate = false; + boolean cardHasUpdate = false; + boolean aidHasUpdate = false; + boolean ctlsAidHasUpdate = false; + boolean capkHasUpdate = false; + + //logger.debug("Update mode? {}", updateMode); + if(/*forceUpdate*/"UPDATE".equals(updateMode)) { + terminalHasUpdate = true; + cardHasUpdate = true; + aidHasUpdate = true; + ctlsAidHasUpdate = true; + capkHasUpdate = true; + forceUpdate = true; + } else if("NOT_UPDATE".equals(updateMode)) { + terminalHasUpdate = false; + cardHasUpdate = false; + aidHasUpdate = false; + ctlsAidHasUpdate = false; + capkHasUpdate = false; + forceUpdate = false; + } else if("PARTIAL".equals(updateMode)) { + // check first from cache + if(!terminalUpdateCache.getCaches().containsKey(req.getSn())) { + if (!terminalUpdateCache.isFull()) { + boolean[] updates = terminalHasUpdateExt(req.getSn(), lastInitTime); + + //logger.debug("Cache size before: {} - {}", terminalUpdateCache.getCaches().size(), terminalUpdateCache.getCurrentCapacity().get()); + + TerminalUpdateCacheObj cacheObj = new TerminalUpdateCacheObj(req.getSn()); + terminalUpdateCache.put(req.getSn(), cacheObj); + + terminalHasUpdate = updates[0]; + cardHasUpdate = updates[1]; + aidHasUpdate = updates[2]; + ctlsAidHasUpdate = updates[2]; + capkHasUpdate = updates[3]; + //logger.debug("0) Terminal Has Update? {}", terminalHasUpdate); + //logger.debug("Cache size after: {} - {}", terminalUpdateCache.getCaches().size(), terminalUpdateCache.getCurrentCapacity().get()); + + } else { + logger.debug("Cache is FULL: {} - {}", terminalUpdateCache.getCaches().size(), terminalUpdateCache.getCurrentCapacity().get()); + // set no update + terminalHasUpdate = false; + cardHasUpdate = false; + aidHasUpdate = false; + ctlsAidHasUpdate = false; + capkHasUpdate = false; + forceUpdate = false; + } + } else { + // already in cache + //logger.debug("SN already in cache!!"); + terminalHasUpdate = false; + cardHasUpdate = false; + aidHasUpdate = false; + ctlsAidHasUpdate = false; + capkHasUpdate = false; + forceUpdate = false; + } + } else { + boolean[] updates = terminalHasUpdateExt(req.getSn(), lastInitTime); + + terminalHasUpdate = updates[0]; + cardHasUpdate = updates[1]; + aidHasUpdate = updates[2]; + ctlsAidHasUpdate = updates[2]; + capkHasUpdate = updates[3]; + } + //logger.debug("Terminal Has Update? {}", terminalHasUpdate); + if(terminalHasUpdate) { + TerminalExt terminalExt = loadTerminalExtBySN(req.getSn()); + if(terminalExt != null) { + LoadContext loadContext = LoadContext.create(TerminalExt.class); + loadContext.setQueryString("select t from tms$TerminalExt t where t.id=:id"); + loadContext.getQuery().setParameter("id", terminalExt.getId()); + loadContext.setView("terminalExt-rest-view"); + terminalExt = dataManager.load(loadContext); + + // set default values + setDefaultValues(terminalExt); + + result.setData(terminalExt); + } + } else { + // no terminal update + } + updateTerminalData.setUpdateTerminal(terminalHasUpdate); + updateTerminalData.setUpdateCard(cardHasUpdate); + updateTerminalData.setUpdateAid(aidHasUpdate); + updateTerminalData.setUpdateCtlsAid(ctlsAidHasUpdate); + updateTerminalData.setUpdateCapk(capkHasUpdate); + + updateTerminalData.setKeepBatch(true); + result.setDataExt(updateTerminalData); + result.setInitTime(new Date()); + + TerminalLastUpdate terminalLastUpdate = metadata.create(TerminalLastUpdate.class); + terminalLastUpdate.setSn(req.getSn()); + terminalLastUpdate.setForceUpdate(forceUpdate); + terminalLastUpdate.setHasUpdate(terminalHasUpdate); + terminalLastUpdate.setLastInitTime(lastInitTime); + dataManager.commit(terminalLastUpdate); + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseResult ackParameterUpdate(AckParameterRequest req) { + BaseResult result = new BaseResult(); + try { + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + Date syncStartTime = getLastInitDate(req.getSyncStartTime()); + Date syncEndTime = getLastInitDate(req.getSyncEndTime()); + + TerminalAckUpdate terminalAckUpdate = metadata.create(TerminalAckUpdate.class); + terminalAckUpdate.setSn(req.getSn()); + terminalAckUpdate.setLastInitTime(lastInitTime); + terminalAckUpdate.setSyncStartTime(syncStartTime); + terminalAckUpdate.setSyncEndTime(syncEndTime); + terminalAckUpdate.setRetryCount(req.getRetryCount()); + terminalAckUpdate.setStatus(req.getStatus()); + dataManager.commit(terminalAckUpdate); + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public void updateTerminalUpdateCaches() { + terminalUpdateCache.runUpdateStatus(); + } + + @Override + public void cleanupTerminalUpdateCaches() { + terminalUpdateCache.cleanupCache(); + } + + private Date getLastInitDate(Object _date) { + if(_date == null) return null; + if(_date instanceof String) { + try { + return fullTimestampDateFormat.parse((String) _date); + } catch(Exception ex) { + return null; + } + } else if(_date instanceof Integer) { + int intDate = (Integer) _date; + if(intDate == 0) return null; + } + return null; + } + + private boolean validateAddTerminalRequest(AddTerminalRequest req, BaseResult result) { + boolean valid = true; + if(req.getSn() == null || "".equals(req.getSn().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getImei() == null || "".equals(req.getImei().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getMerchantId() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + /* + if(req.getProfileId() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + }*/ + if(req.getModelId() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + return valid; + } + + private boolean validateAddTerminalGroupRequest(AddTerminalGroupRequest req, BaseResult result) { + boolean valid = true; + if(req.getName() == null || "".equals(req.getName().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + return valid; + } + + private boolean validateEditTerminalGroupRequest(EditTerminalGroupRequest req, BaseResult result) { + boolean valid = true; + if(req.getId() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getName() == null || "".equals(req.getName().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + return valid; + } + + private boolean validateTerminalAssignRequest(TerminalAssignRequest req, BaseResult result) { + boolean valid = true; + if(req.getGroupId() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getSn() == null || "".equals(req.getSn().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + return valid; + } + + private boolean validateAddApplicationRequest(AddApplicationRequest req, BaseResult result) { + boolean valid = true; + if(req.getName() == null || "".equals(req.getName().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getCompanyName() == null || "".equals(req.getCompanyName().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getApkFileId() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + return valid; + } + + private boolean validateAddDownloadTaskRequest(AddDownloadTaskRequest req, BaseResult result) { + boolean valid = true; + if(req.getName() == null || "".equals(req.getName().trim())) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getDownloadTimeType() == null || (req.getDownloadTimeType() != 1 && req.getDownloadTimeType() != 2)) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } else if(req.getDownloadTimeType() == 2) { + if(req.getDownloadTime() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + } + if(req.getInstallationTimeType() == null || (req.getInstallationTimeType() != 1 && req.getInstallationTimeType() != 2)) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } else if(req.getInstallationTimeType() == 2) { + if(req.getInstallationTime() == null) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + } + if(req.getInstallationNotification() == null || (req.getInstallationNotification() != 1 && req.getInstallationNotification() != 2)) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getApplicationIds() == null || req.getApplicationIds().isEmpty()) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + if(req.getTerminalGroupIds() == null || req.getTerminalGroupIds().isEmpty()) { + result.setResponseCode("0074"); + result.setResponseDesc("invalid-params"); + valid = false; + } + + return valid; + } + + private DeviceProfile loadProfile(UUID id) { + LoadContext loadContext = LoadContext.create(DeviceProfile.class); + loadContext.setId(id); + return dataManager.load(loadContext); + } + + private Merchant loadMerchant(UUID id) { + LoadContext loadContext = LoadContext.create(Merchant.class); + loadContext.setId(id); + return dataManager.load(loadContext); + } + + private DeviceModel loadModel(UUID id) { + LoadContext loadContext = LoadContext.create(DeviceModel.class); + loadContext.setId(id); + return dataManager.load(loadContext); + } + + private FileDescriptor loadFileDescriptor(UUID id) { + LoadContext loadContext = LoadContext.create(FileDescriptor.class); + loadContext.setId(id); + return dataManager.load(loadContext); + } + + private TerminalGroup loadTerminalGroup(UUID id) { + LoadContext loadContext = LoadContext.create(TerminalGroup.class); + loadContext.setId(id); + loadContext.setView("terminalGroup-view"); + return dataManager.load(loadContext); + } + + private Terminal loadTerminalBySN(String sn) { + LoadContext 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", sn.toLowerCase()); + loadContext.setView("terminal-view"); + return dataManager.load(loadContext); + } + + private Terminal loadTerminalMinimalBySN(String sn) { + LoadContext 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", sn.toLowerCase()); + loadContext.setView("terminal-no-acquirers-view"); + return dataManager.load(loadContext); + } + + private Terminal loadTerminalMinimalOnlyProfileIdBySN(String sn) { + LoadContext 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", sn.toLowerCase()); + loadContext.setView("terminal-no-acquirers-only-profileid-view"); + return dataManager.load(loadContext); + } + + private Double _getValueFromQuery(String query) { + QueryRunner runner = new QueryRunner(persistence.getDataSource()); + try { + Set numbers = runner.query(query, + new ResultSetHandler>() { + @Nullable + @Override + public Set handle(ResultSet rs) throws SQLException { + Set rows = new HashSet(); + 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 boolean[] _getTerminalExtUpdates(String query) { + QueryRunner runner = new QueryRunner(persistence.getDataSource()); + try { + boolean[] booleans = runner.query(query, + new ResultSetHandler() { + @Nullable + @Override + public boolean[] handle(ResultSet rs) throws SQLException { + boolean[] _booleans = new boolean[4]; + if (rs.next()) { + boolean terminalUpdate = rs.getBoolean(1); + boolean cardUpdate = rs.getBoolean(2); + boolean aidUpdate = rs.getBoolean(3); + boolean capkUpdate = rs.getBoolean(4); + //logger.info("Terminal update? {}", terminalUpdate); + //logger.info("Card update? {}", cardUpdate); + //logger.info("Aid update? {}", aidUpdate); + //logger.info("Capk update? {}", capkUpdate); + + _booleans = new boolean[] { + terminalUpdate, cardUpdate, aidUpdate, capkUpdate + }; + } + return _booleans; + } + }); + //logger.info("Booleans: {}", booleans); + return booleans; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private boolean terminalHasUpdate(String sn, Date lastInitTime) { + String formattedDate = null; + if(lastInitTime != null) { + formattedDate = timestampDateFormat.format(lastInitTime); + } else { + formattedDate = "1970-01-01 00:00:00"; + } + Double value = null; + value = _getValueFromQuery("" + + "select sum(t0.total) total " + + "from ( " + + " select count(*) total " + + " from tms_terminal tt " + + " inner join tms_terminal_link ttl on tt.id = ttl.terminal_id " + + " inner join tmsext_terminal_ext tte on ttl.terminal_ext_id = tte.id and tte.delete_ts is null " + + " inner join tms_device_profile tdp on tt.profile_id=tdp.id " + + " inner join tms_device_profile_acquirer_link tdpal on tdpal.device_profile_id=tdp.id " + + " inner join tmsext_acquirer ta on tdpal.acquirer_id=ta.id " + + " inner join tmsext_issuer ti on ti.acquirer_id = ta.id and ti.delete_ts is null " + + " left join tmsext_tle_setting tts on ta.tle_setting_id=tts.id " + + " where lower(tt.sn)=lower('"+sn.toLowerCase()+"') " + + " and tt.delete_ts is null " + + " and ( " + + " greatest(tt.create_ts,tt.update_ts) >= '"+formattedDate+"' or " + + " greatest(ttl.create_ts,ttl.update_ts) >= '"+formattedDate+"' or " + + " greatest(tte.create_ts,tte.update_ts) >= '"+formattedDate+"' or " + + " greatest(tdp.create_ts,tdp.update_ts) >= '"+formattedDate+"' or " + + " greatest(tts.create_ts,tts.update_ts) >= '"+formattedDate+"' or " + + " greatest(ta.create_ts,ta.update_ts) >= '"+formattedDate+"' or " + + " greatest(ti.create_ts,ti.update_ts) >= '"+formattedDate+"' or " + + " greatest(tts.create_ts,tts.update_ts) >= '"+formattedDate+"' " + + " ) " + + "union " + + " select count(*) total " + + " from tmsext_aid aid " + + " where greatest(aid.create_ts,aid.update_ts) >= '"+formattedDate+"' " + + "union " + + " select count(*) total " + + " from tmsext_capk capk " + + " where greatest(capk.create_ts,capk.update_ts) >= '"+formattedDate+"' " + + ") t0"); + //logger.info("--> value: '" + value + "'"); + return value != null ? value.intValue() > 0 : false; + } + + private boolean[] terminalHasUpdateExt(String sn, Date lastInitTime) { + String formattedDate = null; + if(lastInitTime != null) { + formattedDate = timestampDateFormat.format(lastInitTime); + } else { + formattedDate = "1970-01-01 00:00:00"; + } + String query = "" + + "select (count(tt.id)>0) update_terminal, " + + " (count(tcc.id)>0) update_card, " + + " ( " + + " select count(aid.*)>0 " + + " from tmsext_aid aid " + + " where greatest(aid.create_ts,aid.update_ts) >= '"+formattedDate+"' " + + " ) update_aid, " + + " ( " + + " select count(capk.*)>0 " + + " from tmsext_capk capk " + + " where greatest(capk.create_ts,capk.update_ts) >= '"+formattedDate+"' " + + " ) update_capk " + + "from tms_terminal tt " + + " inner join tms_terminal_link ttl on tt.id = ttl.terminal_id " + + " inner join tmsext_terminal_ext tte on ttl.terminal_ext_id = tte.id and tte.delete_ts is null " + + " inner join tms_device_profile tdp on tt.profile_id=tdp.id " + + " inner join tms_device_profile_acquirer_link tdpal on tdpal.device_profile_id=tdp.id " + + " inner join tmsext_acquirer ta on tdpal.acquirer_id=ta.id " + + " inner join tmsext_issuer ti on ti.acquirer_id = ta.id and ti.delete_ts is null " + + " inner join tms_merchant tm on tt.merchant_id = tm.id " + + " left join tmsext_tle_setting tts on ta.tle_setting_id=tts.id " + + " left join ( " + + " select ticl.issuer_id,tc.id,tc.create_ts,tc.update_ts " + + " from tmsext_issuer_card_link ticl " + + " inner join tmsext_card tc on ticl.card_id=tc.id " + + " where greatest(tc.create_ts,tc.update_ts) >= '"+formattedDate+"' " + + " ) tcc on tcc.issuer_id=ti.id " + + "where lower(tt.sn)=lower('"+sn.toLowerCase()+"') " + + " and tt.delete_ts is null " + + " and ( " + + " greatest(tt.create_ts,tt.update_ts) >= '"+formattedDate+"' or " + + " greatest(ttl.create_ts,ttl.update_ts) >= '"+formattedDate+"' or " + + " greatest(tte.create_ts,tte.update_ts) >= '"+formattedDate+"' or " + + " greatest(tdp.create_ts,tdp.update_ts) >= '"+formattedDate+"' or " + + " greatest(tts.create_ts,tts.update_ts) >= '"+formattedDate+"' or " + + " greatest(ta.create_ts,ta.update_ts) >= '"+formattedDate+"' or " + + " greatest(ti.create_ts,ti.update_ts) >= '"+formattedDate+"' or " + + " greatest(tm.create_ts,tm.update_ts) >= '"+formattedDate+"' or " + + " greatest(tts.create_ts,tts.update_ts) >= '"+formattedDate+"' " + + " )"; + //logger.info("Query:\n{}", query); + boolean[] values = _getTerminalExtUpdates(query); + return values; + } + + private TerminalExt loadTerminalExtBySN(String sn) { + return loadTerminalExtBySN(sn, "terminalLink-view"); + } + + private TerminalExt loadTerminalExtBySN(String sn, String terminalExtView) { + LoadContext 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", sn.toLowerCase()); + loadContext.setView("terminal-view"); + Terminal terminal = dataManager.load(loadContext); + + if(terminal != null) { + LoadContext loadContextTerminalLink = LoadContext.create(TerminalLink.class); + loadContextTerminalLink.setQueryString("select t from tms_TerminalLink t where t.terminal.id=:terminalId"); + loadContextTerminalLink.getQuery().setParameter("terminalId", terminal.getId()); + loadContextTerminalLink.setView(terminalExtView); + TerminalLink terminalLink = dataManager.load(loadContextTerminalLink); + return terminalLink != null ? terminalLink.getTerminalExt() : null; + } + return null; + } + + private Object[] loadTerminalsExtBySN(String sn, String terminalView, String terminalExtView) { + LoadContext 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", sn.toLowerCase()); + loadContext.setView(terminalView); + Terminal terminal = dataManager.load(loadContext); + + Object[] returns = new Object[2]; + returns[0] = terminal; + if(terminal != null) { + LoadContext loadContextTerminalLink = LoadContext.create(TerminalLink.class); + loadContextTerminalLink.setQueryString("select t from tms_TerminalLink t where t.terminal.id=:terminalId"); + loadContextTerminalLink.getQuery().setParameter("terminalId", terminal.getId()); + loadContextTerminalLink.setView(terminalExtView); + TerminalLink terminalLink = dataManager.load(loadContextTerminalLink); + //return terminalLink != null ? terminalLink.getTerminalExt() : null; + returns[1] = terminalLink != null ? terminalLink.getTerminalExt() : null; + } + return returns; + } + + private Application loadApplication(UUID id) { + LoadContext loadContext = LoadContext.create(Application.class); + loadContext.setId(id); + return dataManager.load(loadContext); + } + + private int pageSize(int totalCount, int pageSize) { + int total = totalCount / pageSize; + int mode = totalCount % pageSize; + if (mode > 0) { + total++; + } + return total; + } + + private String buildAid(Aid _aid) throws Exception { + String aid = _aid.getAid(); + String aidVer = _aid.getAidVersion(); + String tacDefault = _aid.getTacDefault(); + String tacDenial = _aid.getTacDenial(); + String tacOnline = _aid.getTacOnline(); + String threshold = _aid.getThreshold(); + String targetPercentage = _aid.getTargetPercentage(); + String maxTargetPercentage = _aid.getMaxTargetPercentage(); + String ddol = _aid.getDdol(); + String tdol = _aid.getTdol(); + String floorLimit = _aid.getFloorLimit(); + String appSelect = _aid.getAppSelect(); + String aidPriority = _aid.getAidPriority(); + String trxType9C = _aid.getTrxType9C(); + String categoryCode = _aid.getCategoryCode(); + String clTrxLimit = _aid.getClTrxLimit(); + String clCVMLimit = _aid.getClCvmLimit(); + String clFloorLimit = _aid.getClFloorLimit(); + String countryCode = "0360"; + String currencyCode = "0360"; + String emvConfigTerminalCapability = _aid.getEmvConfTermCapability(); + if(emvConfigTerminalCapability == null) { + emvConfigTerminalCapability = ""; + } + String additionalTerminalCapabilities = _aid.getAdditionalTermCapability(); + if(additionalTerminalCapabilities == null) { + additionalTerminalCapabilities = ""; + } + + Object[][] values = {{"9f06", ISOUtil.hex2byte(aid), "AID"}, {"9f09", ISOUtil.hex2byte(aidVer), "AID Ver"}, {"df11", ISOUtil.hex2byte(tacDefault), "TAC Default"}, {"df13", ISOUtil.hex2byte(tacDenial), "TAC Denial"}, {"df12", ISOUtil.hex2byte(tacOnline), "TAC Online"}, {"df15", ISOUtil.hex2byte(threshold), "Threshold"}, {"df17", ISOUtil.hex2byte(targetPercentage), "Target Percentage"}, {"df16", ISOUtil.hex2byte(maxTargetPercentage), "Max Target Percentage"}, {"df14", ISOUtil.hex2byte(ddol), "DDOL"}, {"97", ISOUtil.hex2byte(tdol), "TDOL"}, {"9f1b", ISOUtil.hex2byte(floorLimit), "Floor Limit"}, {"df01", ISOUtil.hex2byte(appSelect), "App Select"}, {"87", ISOUtil.hex2byte(aidPriority), "AID Priority"}, {"9c", ISOUtil.hex2byte(trxType9C), "Trx Type9C"}, {"9f15", ISOUtil.hex2byte(categoryCode), "Category Code"}, {"9f1a", ISOUtil.hex2byte(countryCode), "Terminal Country Code"}, {"5f2a", ISOUtil.hex2byte(currencyCode), "Transaction Currency Code"}, {"df19", ISOUtil.hex2byte(clFloorLimit), "CTLS Offline Minimum Limit"}, {"df20", ISOUtil.hex2byte(clTrxLimit), "CTLS Transaction Limit"}, + {"df21", ISOUtil.hex2byte(clCVMLimit), "CVM Limit"}, + {"9f33", ISOUtil.hex2byte(emvConfigTerminalCapability), "EMV Config Terminal Capability"}, + {"9f40", ISOUtil.hex2byte(additionalTerminalCapabilities), "Additional Terminal Capabilities"} + }; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (Object[] value : values) { + String tag = (String) value[0]; + byte[] val = (byte[]) value[1]; + String desc = (String) value[2]; + + BERTLV tlv = new BERTLV(new TagImpl(tag, TagValueType.BINARY, tag, desc), val); + baos.write(tlv.toBERTLVByteArray()); + } + + byte[] finalAID = baos.toByteArray(); + String aidHex = ISOUtil.hexString(finalAID); + //logger.debug("AID: {}", aidHex); + return aidHex; + } + + private String buildContactlessAid(Aid _aid) throws Exception { + String aid = _aid.getAid(); + String aidVer = _aid.getAidVersion(); + String tacDefault = _aid.getTacDefault(); + String tacDenial = _aid.getTacDenial(); + String tacOnline = _aid.getTacOnline(); + String threshold = _aid.getThreshold(); + String targetPercentage = _aid.getTargetPercentage(); + String maxTargetPercentage = _aid.getMaxTargetPercentage(); + String ddol = _aid.getDdol(); + String tdol = _aid.getTdol(); + String floorLimit = _aid.getFloorLimit(); + String appSelect = _aid.getAppSelect(); + String aidPriority = _aid.getAidPriority(); + String trxType9C = _aid.getTrxType9C(); + String categoryCode = _aid.getCategoryCode(); + String clTrxLimit = _aid.getClTrxLimit(); + String clCVMLimit = _aid.getClCvmLimit(); + String clFloorLimit = _aid.getClFloorLimit(); + String countryCode = "0360"; + String currencyCode = "0360"; + String emvConfigTerminalCapability = _aid.getEmvConfTermCapability(); + if(emvConfigTerminalCapability == null) { + emvConfigTerminalCapability = ""; + } + String additionalTerminalCapabilities = _aid.getAdditionalTermCapability(); + if(additionalTerminalCapabilities == null) { + additionalTerminalCapabilities = ""; + } + String dataTtq = _aid.getDataTtq(); + if(dataTtq == null) { + dataTtq = ""; + } + + Object[][] values = {{"9f06", ISOUtil.hex2byte(aid), "AID"}, {"9f09", ISOUtil.hex2byte(aidVer), "AID Ver"}, {"df11", ISOUtil.hex2byte(tacDefault), "TAC Default"}, {"df13", ISOUtil.hex2byte(tacDenial), "TAC Denial"}, {"df12", ISOUtil.hex2byte(tacOnline), "TAC Online"}, {"df15", ISOUtil.hex2byte(threshold), "Threshold"}, {"df17", ISOUtil.hex2byte(targetPercentage), "Target Percentage"}, {"df16", ISOUtil.hex2byte(maxTargetPercentage), "Max Target Percentage"}, {"df14", ISOUtil.hex2byte(ddol), "DDOL"}, {"97", ISOUtil.hex2byte(tdol), "TDOL"}, {"9f1b", ISOUtil.hex2byte(floorLimit), "Floor Limit"}, {"df01", ISOUtil.hex2byte(appSelect), "App Select"}, {"87", ISOUtil.hex2byte(aidPriority), "AID Priority"}, {"9c", ISOUtil.hex2byte(trxType9C), "Trx Type9C"}, {"9f15", ISOUtil.hex2byte(categoryCode), "Category Code"}, {"9f1a", ISOUtil.hex2byte(countryCode), "Terminal Country Code"}, {"5f2a", ISOUtil.hex2byte(currencyCode), "Transaction Currency Code"}, {"df19", ISOUtil.hex2byte(clFloorLimit), "CTLS Offline Minimum Limit"}, {"df20", ISOUtil.hex2byte(clTrxLimit), "CTLS Transaction Limit"}, + {"df21", ISOUtil.hex2byte(clCVMLimit), "CVM Limit"}, + {"9f33", ISOUtil.hex2byte(emvConfigTerminalCapability), "EMV Config Terminal Capability"}, + {"9f40", ISOUtil.hex2byte(additionalTerminalCapabilities), "Additional Terminal Capabilities"}, + {"9f66", ISOUtil.hex2byte(dataTtq), "Data TTQ"} + }; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (Object[] value : values) { + String tag = (String) value[0]; + byte[] val = (byte[]) value[1]; + String desc = (String) value[2]; + + BERTLV tlv = new BERTLV(new TagImpl(tag, TagValueType.BINARY, tag, desc), val); + baos.write(tlv.toBERTLVByteArray()); + } + + byte[] finalAID = baos.toByteArray(); + String aidHex = ISOUtil.hexString(finalAID); + //logger.debug("AID: {}", aidHex); + return aidHex; + } + + private String buildCapk(Capk capk) throws Exception { + String exp = capk.getExponent(); + String ridIdx = capk.getIdx(); + String rid = capk.getRid(); + String modulus = capk.getModulus(); + String encAlgo = capk.getAlgo(); + String hashAlgo = "01"; + String hash = capk.getHash(); + Date expDate = capk.getExpiryDate(); + if (expDate == null) { + Calendar cal = (Calendar) Calendar.getInstance().clone(); + cal.set(5, 31); + cal.set(2, 12); + cal.add(1, 25); + expDate = cal.getTime(); + } + String expired = this.sdfYMD.format(expDate); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BERTLV tlv = new BERTLV(new TagImpl("9f06", TagValueType.BINARY, "9f06", "RID"), ISOUtil.hex2byte(rid)); + baos.write(tlv.toBERTLVByteArray()); + tlv = new BERTLV(new TagImpl("9f22", TagValueType.BINARY, "9f22", "CAPK Idx"), ISOUtil.hex2byte(ridIdx)); + baos.write(tlv.toBERTLVByteArray()); + tlv = new BERTLV(new TagImpl("df05", TagValueType.BINARY, "df05", "Expired Key"), expired.getBytes()); + baos.write(tlv.toBERTLVByteArray()); + tlv = new BERTLV(new TagImpl("df06", TagValueType.BINARY, "df06", "Hash Algo"), ISOUtil.hex2byte(hashAlgo)); + baos.write(tlv.toBERTLVByteArray()); + tlv = new BERTLV(new TagImpl("df07", TagValueType.BINARY, "df07", "Enc Algo"), ISOUtil.hex2byte(encAlgo)); + baos.write(tlv.toBERTLVByteArray()); + tlv = new BERTLV(new TagImpl("df02", TagValueType.BINARY, "df02", "Modulus"), ISOUtil.hex2byte(modulus)); + baos.write(tlv.toBERTLVByteArray()); + tlv = new BERTLV(new TagImpl("df04", TagValueType.BINARY, "df04", "Exponent"), ISOUtil.hex2byte(exp)); + baos.write(tlv.toBERTLVByteArray()); + tlv = new BERTLV(new TagImpl("df03", TagValueType.BINARY, "df03", "Hash"), ISOUtil.hex2byte(hash)); + baos.write(tlv.toBERTLVByteArray()); + + byte[] finalCAPK = baos.toByteArray(); + String capkHex = ISOUtil.hexString(finalCAPK); + //this.logger.debug("CAPK: {}" + capkHex); + return capkHex; + } + + public boolean normalizeBoolean(Boolean val) { + if(val != null) { + return val.booleanValue(); + } + return false; + } + + @Override + public void onTerminalUpdateProfile(Terminal terminal) { + logger.info("onTerminalUpdateProfile: {}, {}", terminal.getId(), terminal.getProfile().getId()); + Map> terminalProfileCache = (Map) Singleton.getInstance("terminal-profile-cache").getObject(); + if(terminalProfileCache == null) { + terminalProfileCache = new HashMap<>(); + Singleton.getInstance("terminal-cache").setObject(terminalProfileCache); + } + terminalProfileCache.put(terminal.getSn(), new ExpirableObject(terminal, expirationCache)); + } + + @Override + public void onProfileUpdate(DeviceProfile profile) { + logger.info("onProfileUpdate: {}, {}", profile.getId()); + Map> profileCache = (Map) Singleton.getInstance("profile-cache").getObject(); + if(profileCache == null) { + profileCache = new HashMap<>(); + Singleton.getInstance("profile-cache").setObject(profileCache); + } + + // profile map + Map profileMap = new HashMap<>(); + profileMap.put("id", profile.getId()); + profileMap.put("name", profile.getName()); + profileMap.put("hearbeat_interval", profile.getHeartbeatInterval()); + profileMap.put("diagnostic_interval", profile.getDiagnosticInterval()); + profileMap.put("mask_home_button", normalizeBoolean(profile.getMaskHomeButton())); + profileMap.put("mask_status_button", normalizeBoolean(profile.getMaskStatusBar())); + profileMap.put("schedule_reboot", normalizeBoolean(profile.getScheduleReboot())); + if (profile.getScheduleReboot()) { + profileMap.put("schedule_reboot_time", timeFormat.format(profile.getScheduleRebootTime())); + } + profileMap.put("relocation_alert", normalizeBoolean(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 apps = profile.getApps(); + List appList = new ArrayList<>(); + for (DeviceProfileApp app : apps) { + appList.add(app.getPackageName()); + } + profileMap.put("apps_home_list", appList); + profileCache.put(profile.getId(), new ExpirableObject(profileMap, expirationCache)); + } + + @Override + public BaseDetailResult checkParameterUpdateExt(CheckUpdateRequest req) { + BaseDetailResult result = new BaseDetailResult<>(); + Date lastInitTime = getLastInitDate(req.getLastInitTime()); + String query = "select datas.arr[0],datas.arr[1],datas.arr[2],datas.arr[3],datas.arr[4],datas.arr[5],datas.arr[6] from (" + + "select check_update(?,?) arr " + + ") datas"; + Object[] params = new Object[] { + req.getSn(), + new java.sql.Timestamp(lastInitTime.getTime()) + }; + logger.info("check_update({},{})", + req.getSn(), + new java.sql.Timestamp(lastInitTime.getTime())); + int[] types = new int[] { + Types.VARCHAR, + Types.TIMESTAMP + }; + QueryRunner runner = new QueryRunner(persistence.getDataSource()); + try { + boolean[] datas = runner.query(query, + params, + types, + new ResultSetHandler() { + @Nullable + @Override + public boolean[] handle(ResultSet rs) throws SQLException { + if(rs.next()) { + boolean[] ret = new boolean[7]; + ret[0] = rs.getBoolean(1); + ret[1] = rs.getBoolean(2); + ret[2] = rs.getBoolean(3); + ret[3] = rs.getBoolean(4); + ret[4] = rs.getBoolean(5); + ret[5] = rs.getBoolean(6); + ret[6] = rs.getBoolean(7); + return ret; + } + return null; + } + }); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + + CheckParameterUpdateExt data = new CheckParameterUpdateExt(); + data.setUpdateTerminal(datas[0]); + data.setUpdateAcquirer(datas[1]); + data.setUpdateCard(datas[2]); + data.setUpdateCapk(datas[3]); + data.setUpdateAid(datas[4]); + data.setUpdateCtlsAid(datas[5]); + data.setUpdateResponseCode(datas[6]); + data.setKeepBatch(true); + + result.setData(data); + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseListResult initResponseCode(InitProfileRequest req) { + BaseListResult result = new BaseListResult<>(); + try { + LoadContext loadContext = LoadContext.create(ResponseCode.class); + loadContext.setQueryString("select rc from tms_ResponseCode rc where rc.deleteTs is null"); + loadContext.setView("responseCode-view"); + List list = dataManager.loadList(loadContext); + List listSimple = list.parallelStream().map(responseCode -> { + ResponseCodeSimple rc = new ResponseCodeSimple(); + rc.setId(responseCode.getId()); + rc.setType(responseCode.getType().name()); + rc.setCode(responseCode.getCode()); + rc.setDesc(responseCode.getDesc()); + return rc; + }).collect(Collectors.toList()); + + result.setRows(listSimple); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseDetailResult initTerminalExt(InitProfileRequest req) { + BaseDetailResult result = new BaseDetailResult<>(); + try { + Object[] terminals = loadTerminalsExtBySN(req.getSn(), "terminal-no-acquirers-view", "terminalLink-with-profile-only-view"); + TerminalExt terminalExt = (TerminalExt) terminals[1]; + Terminal terminal = (Terminal) terminals[0]; + if(terminalExt != null) { + if(terminal.getProfile() != null) { + // if not set in terminal, use from profile + if (terminalExt.getHostReport() == null) { + terminalExt.setHostReport(terminal.getProfile().getHostReport()); + } + terminalExt.setHostReportApiKey(terminal.getProfile().getHostReportApiKey()); + terminalExt.setHostReportUrl(terminal.getProfile().getHostReportUrl()); + terminalExt.setHostReportTimeout(terminal.getProfile().getHostReportTimeout()); + // if not set in terminal, use from profile + if (terminalExt.getHostLogging() == null) { + terminalExt.setHostLogging(terminal.getProfile().getHostLogging()); + } + terminalExt.setHostLoggingApiKey(terminal.getProfile().getHostLoggingApiKey()); + terminalExt.setHostLoggingUrl(terminal.getProfile().getHostLoggingUrl()); + terminalExt.setHostLoggingTimeout(terminal.getProfile().getHostLoggingTimeout()); + if (terminalExt.getSkipPassword() == null) { + terminalExt.setSkipPassword(false); + } + + terminalExt.setAutoStartApp(terminal.getProfile().getAutoStartApp() != null ? + terminal.getProfile().getAutoStartApp() : false); + } + + // set default values + setDefaultValues(terminalExt); + + result.setData(terminalExt); + + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + logger.warn("Terminal Ext Not Found: {}", req.getSn()); + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + @Override + public BaseListResult initAcquirer(InitProfileRequest req) { + BaseListResult result = new BaseListResult<>(); + try { + Object[] terminals = loadTerminalsExtBySN(req.getSn(), "terminal-view", "terminalLink-with-profile-acquirer-view"); + Terminal terminal = (Terminal) terminals[0]; + TerminalExt terminalExt = (TerminalExt) terminals[1]; + if(terminal != null) { + List list = terminal.getProfile().getAcquirers(); + if(terminalExt != null) { + list.stream().parallel().forEach(acquirer -> { + // set tid & mid from terminal ext + acquirer.setTerminalID(terminalExt.getTerminalId()); + acquirer.setMerchantID(terminalExt.getMerchantId()); + }); + } + result.setRows(list); + result.setResponseCode("0000"); + result.setResponseDesc("success"); + } else { + logger.warn("Terminal Ext Not Found: {}", req.getSn()); + result.setResponseCode("0404"); + result.setResponseDesc("data-not-found"); + } + } catch (Exception ex) { + logger.error("Exception: {}", ex.getMessage(), ex); + result.setResponseCode("9999"); + result.setResponseDesc("general-error"); + } + return result; + } + + private void setDefaultValues(TerminalExt terminalExt) { + // to handle null values + if(terminalExt.getFallbackEnabled() == null) { + terminalExt.setFallbackEnabled(false); + } + if(terminalExt.getFeatureManualKeyIn() == null) { + terminalExt.setFeatureManualKeyIn(false); + } + if(terminalExt.getFeatureSaleFareNonFare() == null) { + terminalExt.setFeatureSaleFareNonFare(false); + } + if(terminalExt.getFeatureInstallment() == null) { + terminalExt.setFeatureInstallment(false); + } + if(terminalExt.getFeatureSaleCompletion() == null) { + terminalExt.setFeatureSaleCompletion(false); + } + if(terminalExt.getFeatureCardVerification() == null) { + terminalExt.setFeatureCardVerification(false); + } + if(terminalExt.getFeatureSaleRedemption() == null) { + terminalExt.setFeatureSaleRedemption(false); + } + if(terminalExt.getFeatureSaleTip() == null) { + terminalExt.setFeatureSaleTip(false); + } + if(terminalExt.getFeatureSale() == null) { + terminalExt.setFeatureSale(false); + } + if(terminalExt.getFeatureSaleNfc() == null) { + terminalExt.setFeatureSaleNfc(false); + } + if(terminalExt.getFeatureRefundNfc() == null) { + terminalExt.setFeatureRefundNfc(false); + } + if(terminalExt.getFeatureSaleWithBripoin() == null) { + terminalExt.setFeatureSaleWithBripoin(false); + } + if(terminalExt.getInquiryBripoinTimeout() == null) { + terminalExt.setInquiryBripoinTimeout(0); + } + if(terminalExt.getFeatureReleaseCardVer() == null) { + terminalExt.setFeatureReleaseCardVer(false); + } + if(terminalExt.getRandomPinKeypad() == null) { + terminalExt.setRandomPinKeypad(false); + } + if(terminalExt.getBeepPinKeypad() == null) { + terminalExt.setBeepPinKeypad(false); + } + if(terminalExt.getAutoLogon() == null) { + terminalExt.setAutoLogon(false); + } + /** + * 2024-10-23 + */ + if(terminalExt.getFeatureVoid() == null) { + terminalExt.setFeatureVoid(false); + } + if(terminalExt.getFeatureSettlement() == null) { + terminalExt.setFeatureSettlement(false); + } + if(terminalExt.getFeatureReprint() == null) { + terminalExt.setFeatureReprint(false); + } + if(terminalExt.getFeatureReport() == null) { + terminalExt.setFeatureReport(false); + } + if(terminalExt.getFeatureQrisGenerate() == null) { + terminalExt.setFeatureQrisGenerate(false); + } + if(terminalExt.getFeatureQrisPay() == null) { + terminalExt.setFeatureQrisPay(false); + } + if(terminalExt.getFeatureQrisRefund() == null) { + terminalExt.setFeatureQrisRefund(false); + } + if(terminalExt.getFeatureQrisReport() == null) { + terminalExt.setFeatureQrisReport(false); + } + if(terminalExt.getFeatureBrizziInfo() == null) { + terminalExt.setFeatureBrizziInfo(false); + } + if(terminalExt.getFeatureBrizziInfoDeposit() == null) { + terminalExt.setFeatureBrizziInfoDeposit(false); + } + if(terminalExt.getFeatureBrizziUpdateDeposit() == null) { + terminalExt.setFeatureBrizziUpdateDeposit(false); + } + if(terminalExt.getFeatureBrizziTopup() == null) { + terminalExt.setFeatureBrizziTopup(false); + } + if(terminalExt.getFeatureBrizziTopupDeposit() == null) { + terminalExt.setFeatureBrizziTopupDeposit(false); + } + if(terminalExt.getFeatureBrizziSale() == null) { + terminalExt.setFeatureBrizziSale(false); + } + if(terminalExt.getFeatureBrizziSettlement() == null) { + terminalExt.setFeatureBrizziSettlement(false); + } + if(terminalExt.getFeatureBrizziVoid() == null) { + terminalExt.setFeatureBrizziVoid(false); + } + if(terminalExt.getFeatureBrizziInit() == null) { + terminalExt.setFeatureBrizziInit(false); + } + if(terminalExt.getFeatureBrizziCardInfo() == null) { + terminalExt.setFeatureBrizziCardInfo(false); + } + if(terminalExt.getFeatureBrizziLog() == null) { + terminalExt.setFeatureBrizziLog(false); + } + if(terminalExt.getFeatureBrizziReprint() == null) { + terminalExt.setFeatureBrizziReprint(false); + } + if(terminalExt.getFeatureBrizziReport() == null) { + terminalExt.setFeatureBrizziReport(false); + } + if(terminalExt.getFeatureReEngQris() == null) { + terminalExt.setFeatureReEngQris(false); + } + + if(terminalExt.getFeatureContactlessQristap() == null) { + terminalExt.setFeatureContactlessQristap(false); + } + + if(terminalExt.getPasswordBlockTime() == null) { + terminalExt.setPasswordBlockTime(0); + } + + if(terminalExt.getAutoDeleteQrisTrx() == null) { + terminalExt.setAutoDeleteQrisTrx(0); + } + + if(terminalExt.getSettleMaxTrxCountBrizzi() == null) { + terminalExt.setSettleMaxTrxCountBrizzi(0); + } + + if(terminalExt.getSettleWarningTrxCountBrizzi() == null) { + terminalExt.setSettleWarningTrxCountBrizzi(0); + } + + if(terminalExt.getQrisCekInterval() == null) { + terminalExt.setQrisCekInterval(0); + } + + /** + * 2026-01-04 + */ + if(terminalExt.getCustomPanMasking() == null) { + terminalExt.setCustomPanMasking(false); + } + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/ApkServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/ApkServiceBean.java new file mode 100644 index 0000000..64ae95d --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/ApkServiceBean.java @@ -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; + } + } + } + +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/ChartDataServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/ChartDataServiceBean.java new file mode 100644 index 0000000..c263bb4 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/ChartDataServiceBean.java @@ -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 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 datas = runner.query(query, + params, + types, + new ResultSetHandler>() { + @Nullable + @Override + public Set handle(ResultSet rs) throws SQLException { + Set rows = new HashSet(); + 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); + } + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/DeleteTaskServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/DeleteTaskServiceBean.java new file mode 100644 index 0000000..bec635f --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/DeleteTaskServiceBean.java @@ -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 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 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 applications = task.getApplications(); + // get the terminals + List terminalGroups = task.getTerminalGroups(); + List terminals = new ArrayList<>(); + terminalGroups.forEach(terminalGroup -> { + List _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 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 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() { + @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); + } + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/DeviceInitServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/DeviceInitServiceBean.java new file mode 100644 index 0000000..5318afa --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/DeviceInitServiceBean.java @@ -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 apps = profile.getApps(); + List 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 apps = profile.getApps(); + List 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); + } + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/DownloadTaskServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/DownloadTaskServiceBean.java new file mode 100644 index 0000000..b648037 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/DownloadTaskServiceBean.java @@ -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 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 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 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 terminalGroups = task.getTerminalGroups(); + List terminals = new ArrayList<>(); + terminalGroups.forEach(terminalGroup -> { + List _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 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 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() { + @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(); + } + } + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/EchoServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/EchoServiceBean.java new file mode 100644 index 0000000..7c00e6c --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/EchoServiceBean.java @@ -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"); + } + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/FileServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/FileServiceBean.java new file mode 100644 index 0000000..ebf5b79 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/FileServiceBean.java @@ -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 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(); + } + } + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/HeartBeatServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/HeartBeatServiceBean.java new file mode 100644 index 0000000..a6853cc --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/HeartBeatServiceBean.java @@ -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; + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/LicenseServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/LicenseServiceBean.java new file mode 100644 index 0000000..e34821d --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/LicenseServiceBean.java @@ -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(); + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/NumericInfoWidgetServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/NumericInfoWidgetServiceBean.java new file mode 100644 index 0000000..631b99e --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/NumericInfoWidgetServiceBean.java @@ -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 numbers = runner.query(query, + new ResultSetHandler>() { + @Nullable + @Override + public Set handle(ResultSet rs) throws SQLException { + Set rows = new HashSet(); + 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 numbers = runner.query(query, + new String[] { tenantId }, + new int[] { Types.VARCHAR }, + new ResultSetHandler>() { + @Nullable + @Override + public Set handle(ResultSet rs) throws SQLException { + Set rows = new HashSet(); + 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; + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/ReportServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/ReportServiceBean.java new file mode 100644 index 0000000..b855044 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/ReportServiceBean.java @@ -0,0 +1,1646 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.config.ReportConfig; +import com.cmobile.unifiedtms.entity.ExportReportBean; +import com.cmobile.unifiedtms.entity.enums.ExportType; +import com.cmobile.unifiedtms.entity.enums.ReportType; +import com.cmobile.unifiedtms.entity.misc.CellInfo; +import com.cmobile.unifiedtms.entity.misc.FileDownloadWrapper; +import com.cmobile.unifiedtms.entity.restmodel.result.BaseDetailResult; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.haulmont.addon.sdbmt.core.app.multitenancy.TenantProvider; +import com.haulmont.cuba.core.Persistence; +import com.haulmont.cuba.core.Query; +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.DataManager; +import org.apache.commons.net.PrintCommandListener; +import org.apache.commons.net.ftp.FTP; +import org.apache.commons.net.ftp.FTPSClient; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.inject.Inject; +import java.io.*; +import java.lang.reflect.Type; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.*; + +@Service(ReportService.NAME) +public class ReportServiceBean implements ReportService { + + private Logger logger = LoggerFactory.getLogger(ReportServiceBean.class); + @Inject + private Persistence persistence; + @Inject + private ReportConfig reportConfig; + @Inject + private FileService fileService; + @Inject + private DataManager dataManager; + @Inject + private FileStorageAPI fileStorageAPI; + @Inject + private TenantProvider tenantProvider; + private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyyMMdd_HHmm"); + private SimpleDateFormat shortDateFormat = new SimpleDateFormat("yyMMdd"); + private SimpleDateFormat fullDateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + + @Override + public ExportReportBean exportReport(ReportType reportType, ExportType exportType) throws Exception { + switch(reportType) { + case DIAGNOSTIC_REPORT: + return exportTerminalReport(exportType); + case ACK_REPORT: + return exportAckReport(exportType); + } + return null; + } + + /** + * Export Terminal Report + * @param type + * @return + * @throws Exception + */ + private ExportReportBean exportTerminalReport(ExportType type) throws Exception { + ExportReportBean report = new ExportReportBean(); + try { + report.setFilename(dateFormat.format(new Date()) + "_terminal_report" + (type == ExportType.CSV ? ".csv" : ".xlsx")); + + StringWriter sw = new StringWriter(); + Workbook workbook = null; + Sheet sheet = null; + if(type == ExportType.CSV) { + // headers + sw.append("sn,imei,terminal_id,merchant_id,merchant_name1,merchant_name2,merchant_name3,feature_sale,feature_sale_tip,feature_sale_redemption,feature_card_verification,feature_sale_completion,feature_installment,feature_sale_fare_non_fare,feature_manual_key_in,feature_qris,feature_contactless,random_pin_keypad,beep_pin_keypad,auto_logon,next_logon,installment1_options,installment2_options,installment3_options,state,app_version,launcher_version,vfs_version,vfss_version,ECR_version,ROM_version,security_patch_version,update_ts,last_diagnostic_time,last_heartbeat_time,latitude,longitude,sam_available,wifi_ssid,wifi_strength,cell_name,cell_type,cell_strength,push_logon,host_report,host_logging").append("\n"); + } else if(type == ExportType.XLS) { + workbook = new XSSFWorkbook(); + sheet = workbook.createSheet("Diagnostic Report"); + + Row header = sheet.createRow(0); + + CellStyle headerStyle = workbook.createCellStyle(); + XSSFFont font = ((XSSFWorkbook) workbook).createFont(); + font.setFontName("Calibri"); + font.setFontHeightInPoints((short) 11); + font.setBold(true); + headerStyle.setFont(font); + + Cell headerCell = header.createCell(0); + headerCell.setCellValue("sn"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(1); + headerCell.setCellValue("imei"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(2); + headerCell.setCellValue("terminal_id"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(3); + headerCell.setCellValue("merchant_id"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(4); + headerCell.setCellValue("merchant_name1"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(5); + headerCell.setCellValue("merchant_name2"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(6); + headerCell.setCellValue("merchant_name3"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(7); + headerCell.setCellValue("feature_sale"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(8); + headerCell.setCellValue("feature_sale_tip"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(9); + headerCell.setCellValue("feature_sale_redemption"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(10); + headerCell.setCellValue("feature_card_verification"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(11); + headerCell.setCellValue("feature_sale_completion"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(12); + headerCell.setCellValue("feature_installment"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(13); + headerCell.setCellValue("feature_sale_fare_non_fare"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(14); + headerCell.setCellValue("feature_manual_key_in"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(15); + headerCell.setCellValue("feature_qris"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(16); + headerCell.setCellValue("feature_contactless"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(17); + headerCell.setCellValue("random_pin_keypad"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(18); + headerCell.setCellValue("beep_pin_keypad"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(19); + headerCell.setCellValue("auto_logon"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(20); + headerCell.setCellValue("next_logon"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(21); + headerCell.setCellValue("installment1_options"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(22); + headerCell.setCellValue("installment2_options"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(23); + headerCell.setCellValue("installment3_options"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(24); + headerCell.setCellValue("state"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(25); + headerCell.setCellValue("app_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(26); + headerCell.setCellValue("launcher_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(27); + headerCell.setCellValue("vfs_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(28); + headerCell.setCellValue("vfss_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(29); + headerCell.setCellValue("ECR_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(30); + headerCell.setCellValue("ROM_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(31); + headerCell.setCellValue("security_patch_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(32); + headerCell.setCellValue("update_ts"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(33); + headerCell.setCellValue("last_diagnostic_time"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(34); + headerCell.setCellValue("last_heartbeat_time"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(35); + headerCell.setCellValue("latitude"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(36); + headerCell.setCellValue("longitude"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(37); + headerCell.setCellValue("sam_available"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(38); + headerCell.setCellValue("wifi_name"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(39); + headerCell.setCellValue("wifi_strength"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(40); + headerCell.setCellValue("cell_name"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(41); + headerCell.setCellValue("cell_type"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(42); + headerCell.setCellValue("cell_strength"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(43); + headerCell.setCellValue("push_logon"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(44); + headerCell.setCellValue("host_report"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(45); + headerCell.setCellValue("host_logging"); + headerCell.setCellStyle(headerStyle); + } + + // reusable - detail style : that's why defined here + CellStyle detailStyle = null; + if(type == ExportType.XLS) { + // reusable - detail style : that's why defined here + detailStyle = workbook.createCellStyle(); + CreationHelper createHelper = workbook.getCreationHelper(); + detailStyle.setDataFormat( + createHelper.createDataFormat().getFormat("yyyy-mm-dd hh:mm:ss")); + XSSFFont font = ((XSSFWorkbook) workbook).createFont(); + font.setFontName("Calibri"); + font.setFontHeightInPoints((short) 11); + detailStyle.setFont(font); + } + + // query + Transaction tx = persistence.createTransaction(); + try { + Query query = persistence.getEntityManager().createNativeQuery( + "SELECT " + + "sn, imei, terminal_id, merchant_id, merchant_name1, merchant_name2, merchant_name3, " + + "feature_sale, feature_sale_tip, feature_sale_redemption, feature_card_verification, " + + "feature_sale_completion, feature_installment, feature_sale_fare_non_fare, feature_manual_key_in, " + + "feature_qris, feature_contactless, random_pin_keypad, beep_pin_keypad, auto_logon, next_logon, " + + "installment1_options, installment2_options, installment3_options, state, app_version, launcher_version, " + + "vfs_version, vfss_version," + + "null ecr_version,rom_version,sp_version," + + "update_ts, last_diagnostic_time, last_heartbeat_time, " + + "latitude,longitude, " + + "wifi_name,wifi_strength, " + + "cell_name,cell_type,cell_strength, " + + "push_logon,host_report,host_logging, " + + "installed_apps_string, " + + "sam_available " + + "FROM public.tms_v_terminal_report"); + List list = query.getResultList(); + int rowNum = 0; + Gson gson = new Gson(); + for (Iterator it = list.iterator(); it.hasNext(); ) { + Object[] row = (Object[]) it.next(); + + String sn = (String) row[0]; + String imei = (String) row[1]; + String terminalId = (String) row[2]; + String merchantId = (String) row[3]; + String merchantName1 = (String) row[4]; + String merchantName2 = (String) row[5]; + String merchantName3 = (String) row[6]; + Boolean featureSale = (Boolean) row[7]; + Boolean featureSaleTip = (Boolean) row[8]; + Boolean featureSaleRedemption = (Boolean) row[9]; + Boolean featureCardVerification = (Boolean) row[10]; + Boolean featureSaleCompletion = (Boolean) row[11]; + Boolean featureInstallment = (Boolean) row[12]; + Boolean featureSaleFareNonFare = (Boolean) row[13]; + Boolean featureManualKeyIn = (Boolean) row[14]; + Boolean featureQris = (Boolean) row[15]; + Boolean featureContactless = (Boolean) row[16]; + Boolean randomPinKeypad = (Boolean) row[17]; + Boolean beepPinKeypad = (Boolean) row[18]; + Boolean autoLogon = (Boolean) row[19]; + Integer nextLogon = (Integer) row[20]; + String installment1Options = (String) row[21]; + String installment2Options = (String) row[22]; + String installment3Options = (String) row[23]; + String state = (String) row[24]; + String appVersion = (String) row[25]; + String launcherVersion = (String) row[26]; + String vsfVersion = (String) row[27]; + String vfssVersion = (String) row[28]; + String ecrVersion = (String) row[29]; + String romVersion = (String) row[30]; + String securityPatchVersion = (String) row[31]; + Timestamp updateTs = (Timestamp) row[32]; + Timestamp lastDiagnosticTime = (Timestamp) row[33]; + Timestamp lastHeartbeatTime = (Timestamp) row[34]; + Double latitude = (Double) row[35]; + Double longitude = (Double) row[36]; + String wifiName = (String) row[37]; + Integer wifiStrength = (Integer) row[38]; + String cellName = (String) row[39]; + String cellType = (String) row[40]; + Integer cellStrength = (Integer) row[41]; + Integer pushLogon = (Integer) row[42]; + Boolean hostReport = (Boolean) row[43]; + Boolean hostLogging = (Boolean) row[44]; + String installedAppString = (String) row[45]; + Boolean samAvailable = (Boolean) row[46]; + if(installedAppString != null) { + Map[] maps = gson.fromJson(installedAppString, Map[].class); + for(Map map : maps) { + String packageName = (String) map.get("package_name"); + if("com.vfi.id.ecr".equals(packageName)) { + ecrVersion = (String) map.get("version"); + } + } + } + + if (type == ExportType.CSV) { + sw.append(sn).append(","); + sw.append(imei).append(","); + sw.append(terminalId).append(","); + sw.append(merchantId).append(","); + sw.append(merchantName1).append(","); + sw.append(merchantName2).append(","); + sw.append(merchantName3).append(","); + sw.append(normalizeBoolean(featureSale)).append(","); + sw.append(normalizeBoolean(featureSaleTip)).append(","); + sw.append(normalizeBoolean(featureSaleRedemption)).append(","); + sw.append(normalizeBoolean(featureCardVerification)).append(","); + sw.append(normalizeBoolean(featureSaleCompletion)).append(","); + sw.append(normalizeBoolean(featureInstallment)).append(","); + sw.append(normalizeBoolean(featureSaleFareNonFare)).append(","); + sw.append(normalizeBoolean(featureManualKeyIn)).append(","); + sw.append(normalizeBoolean(featureQris)).append(","); + sw.append(normalizeBoolean(featureContactless)).append(","); + sw.append(normalizeBoolean(randomPinKeypad)).append(","); + sw.append(normalizeBoolean(beepPinKeypad)).append(","); + sw.append(normalizeBoolean(autoLogon)).append(","); + sw.append(normalizeInteger(nextLogon)).append(","); + sw.append(wrap(installment1Options)).append(","); + sw.append(wrap(installment2Options)).append(","); + sw.append(wrap(installment3Options)).append(","); + sw.append(state).append(","); + sw.append(appVersion).append(","); + sw.append(launcherVersion).append(","); + sw.append(vsfVersion).append(","); + sw.append(vfssVersion).append(","); + sw.append(ecrVersion).append(","); + sw.append(romVersion).append(","); + sw.append(securityPatchVersion).append(","); + sw.append(updateTs != null ? fullDateTimeFormat.format(updateTs) : null).append(","); + sw.append(lastDiagnosticTime != null ? fullDateTimeFormat.format(lastDiagnosticTime) : null).append(","); + sw.append(lastHeartbeatTime != null ? fullDateTimeFormat.format(lastHeartbeatTime) : null).append(","); + sw.append(normalizeDouble(latitude)).append(","); + sw.append(normalizeDouble(longitude)).append(","); + sw.append(normalizeBoolean(samAvailable)).append(","); + sw.append(wifiName).append(","); + sw.append(normalizeInteger(wifiStrength)).append(","); + sw.append(cellName).append(","); + sw.append(cellType).append(","); + sw.append(normalizeInteger(cellStrength)).append(","); + sw.append(normalizeInteger(pushLogon)).append(","); + sw.append(normalizeBoolean(hostReport)).append(","); + sw.append(normalizeBoolean(hostLogging)); + + sw.append("\n"); + } else if(type == ExportType.XLS) { + Row detail = sheet.createRow(rowNum+1); + Cell detailCell = detail.createCell(0); + detailCell.setCellValue(sn); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(1); + detailCell.setCellValue(imei); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(2); + detailCell.setCellValue(terminalId); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(3); + detailCell.setCellValue(merchantId); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(4); + detailCell.setCellValue(merchantName1); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(5); + detailCell.setCellValue(merchantName2); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(6); + detailCell.setCellValue(merchantName3); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(7); + detailCell.setCellValue(normalizeBoolean(featureSale)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(8); + detailCell.setCellValue(normalizeBoolean(featureSaleTip)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(9); + detailCell.setCellValue(normalizeBoolean(featureSaleRedemption)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(10); + detailCell.setCellValue(normalizeBoolean(featureCardVerification)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(11); + detailCell.setCellValue(normalizeBoolean(featureSaleCompletion)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(12); + detailCell.setCellValue(normalizeBoolean(featureInstallment)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(13); + detailCell.setCellValue(normalizeBoolean(featureSaleFareNonFare)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(14); + detailCell.setCellValue(normalizeBoolean(featureManualKeyIn)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(15); + detailCell.setCellValue(normalizeBoolean(featureQris)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(16); + detailCell.setCellValue(normalizeBoolean(featureContactless)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(17); + detailCell.setCellValue(normalizeBoolean(randomPinKeypad)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(18); + detailCell.setCellValue(normalizeBoolean(beepPinKeypad)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(19); + detailCell.setCellValue(normalizeBoolean(autoLogon)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(20); + detailCell.setCellValue(normalizeInteger(nextLogon)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(21); + detailCell.setCellValue(installment1Options); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(22); + detailCell.setCellValue(installment2Options); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(23); + detailCell.setCellValue(installment3Options); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(24); + detailCell.setCellValue(state); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(25); + detailCell.setCellValue(appVersion); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(26); + detailCell.setCellValue(launcherVersion); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(27); + detailCell.setCellValue(vsfVersion); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(28); + detailCell.setCellValue(vfssVersion); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(29); + detailCell.setCellValue(ecrVersion); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(30); + detailCell.setCellValue(romVersion); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(31); + detailCell.setCellValue(securityPatchVersion); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(32); + detailCell.setCellValue(normalizeTimestamp(updateTs)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(33); + detailCell.setCellValue(normalizeTimestamp(lastDiagnosticTime)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(34); + detailCell.setCellValue(normalizeTimestamp(lastHeartbeatTime)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(35); + detailCell.setCellValue(normalizeDouble(latitude)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(36); + detailCell.setCellValue(normalizeDouble(longitude)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(37); + detailCell.setCellValue(normalizeBoolean(samAvailable)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(38); + detailCell.setCellValue(wifiName); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(39); + detailCell.setCellValue(normalizeInteger(wifiStrength)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(40); + detailCell.setCellValue(cellName); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(41); + detailCell.setCellValue(cellType); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(42); + detailCell.setCellValue(normalizeInteger(cellStrength)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(43); + detailCell.setCellValue(normalizeInteger(pushLogon)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(44); + detailCell.setCellValue(normalizeBoolean(hostReport)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(45); + detailCell.setCellValue(normalizeBoolean(hostLogging)); + detailCell.setCellStyle(detailStyle); + } + + rowNum++; + } + } finally { + tx.end(); + } + + if(type == ExportType.CSV) { + report.setFileContent(sw.toString().getBytes()); + + sw.close(); + } else if(type == ExportType.XLS) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + workbook.write(baos); + workbook.close(); + + report.setFileContent(baos.toByteArray()); + } + } finally { + } + return report; + } + + /** + * Export ACK Report + * @param type + * @return + * @throws Exception + */ + private ExportReportBean exportAckReport(ExportType type) throws Exception { + ExportReportBean report = new ExportReportBean(); + try { + report.setFilename(dateFormat.format(new Date()) + "_ack_report" + (type == ExportType.CSV ? ".csv" : ".xlsx")); + + StringWriter sw = new StringWriter(); + Workbook workbook = null; + Sheet sheet = null; + if(type == ExportType.CSV) { + // headers + sw.append("sn,status,last_init,last_init_aid,last_init_contactless_aid,last_init_capk,last_init_terminal,last_init_cards").append("\n"); + } else if(type == ExportType.XLS) { + workbook = new XSSFWorkbook(); + sheet = workbook.createSheet("Ack Report"); + + Row header = sheet.createRow(0); + + CellStyle headerStyle = workbook.createCellStyle(); + XSSFFont font = ((XSSFWorkbook) workbook).createFont(); + font.setFontName("Calibri"); + font.setFontHeightInPoints((short) 11); + font.setBold(true); + headerStyle.setFont(font); + + Cell headerCell = header.createCell(0); + headerCell.setCellValue("sn"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(1); + headerCell.setCellValue("status"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(2); + headerCell.setCellValue("last_init"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(3); + headerCell.setCellValue("last_init_aid"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(4); + headerCell.setCellValue("last_init_contactless_aid"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(5); + headerCell.setCellValue("last_init_capk"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(6); + headerCell.setCellValue("last_init_terminal"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(7); + headerCell.setCellValue("last_init_cards"); + headerCell.setCellStyle(headerStyle); + } + + CellStyle detailStyle = null; + if(type == ExportType.XLS) { + // reusable - detail style : that's why defined here + detailStyle = workbook.createCellStyle(); + CreationHelper createHelper = workbook.getCreationHelper(); + detailStyle.setDataFormat( + createHelper.createDataFormat().getFormat("yyyy-mm-dd hh:mm:ss")); + XSSFFont font = ((XSSFWorkbook) workbook).createFont(); + font.setFontName("Calibri"); + font.setFontHeightInPoints((short) 11); + detailStyle.setFont(font); + } + + // query + Transaction tx = persistence.createTransaction(); + try { + Query query = persistence.getEntityManager().createNativeQuery( + "SELECT sn, status, last_init_time, last_init_aid_time, last_init_contactless_aid_time, " + + " last_init_capk_time, last_init_terminal_time, last_init_cards_time " + + "FROM public.tms_v_terminal_ack_update2;\n"); + List list = query.getResultList(); + int rowNum = 0; + for (Iterator it = list.iterator(); it.hasNext(); ) { + Object[] row = (Object[]) it.next(); + + String sn = (String) row[0]; + String status = (String) row[1]; + Timestamp lastInitTs = (Timestamp) row[2]; + Timestamp lastInitAid = (Timestamp) row[3]; + Timestamp lastInitContactlessAid = (Timestamp) row[4]; + Timestamp lastInitCapk = (Timestamp) row[5]; + Timestamp lastInitTerminal = (Timestamp) row[6]; + Timestamp lastInitCards = (Timestamp) row[7]; + + if (type == ExportType.CSV) { + sw.append(sn).append(","); + sw.append(status).append(","); + sw.append(lastInitTs != null ? fullDateTimeFormat.format(lastInitTs) : null).append(","); + sw.append(lastInitAid != null ? fullDateTimeFormat.format(lastInitAid) : null).append(","); + sw.append(lastInitContactlessAid != null ? fullDateTimeFormat.format(lastInitContactlessAid) : null).append(","); + sw.append(lastInitCapk != null ? fullDateTimeFormat.format(lastInitCapk) : null).append(","); + sw.append(lastInitTerminal != null ? fullDateTimeFormat.format(lastInitTerminal) : null).append(","); + sw.append(lastInitCards != null ? fullDateTimeFormat.format(lastInitCards) : null).append(","); + + sw.append("\n"); + } else if(type == ExportType.XLS) { + Row detail = sheet.createRow(rowNum+1); + Cell detailCell = detail.createCell(0); + detailCell.setCellValue(sn); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(1); + detailCell.setCellValue(status); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(2); + detailCell.setCellValue(normalizeTimestamp(lastInitTs)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(3); + detailCell.setCellValue(normalizeTimestamp(lastInitAid)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(4); + detailCell.setCellValue(normalizeTimestamp(lastInitContactlessAid)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(5); + detailCell.setCellValue(normalizeTimestamp(lastInitCapk)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(6); + detailCell.setCellValue(normalizeTimestamp(lastInitTerminal)); + detailCell.setCellStyle(detailStyle); + + detailCell = detail.createCell(7); + detailCell.setCellValue(normalizeTimestamp(lastInitCards)); + detailCell.setCellStyle(detailStyle); + } + + rowNum++; + } + } finally { + tx.end(); + } + + if(type == ExportType.CSV) { + report.setFileContent(sw.toString().getBytes()); + + sw.close(); + } else if(type == ExportType.XLS) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + workbook.write(baos); + workbook.close(); + + report.setFileContent(baos.toByteArray()); + } + } finally { + } + return report; + } + + @Override + public BaseDetailResult exportDiagnosticReport(String vendorName, Date date) throws Exception { + logger.info("exportDiagnosticReport[" + vendorName + ", " + date + "]"); + BaseDetailResult result = new BaseDetailResult<>(); + ExportReportBean report = new ExportReportBean(); + try { + report.setFilename(dateFormat.format(new Date()) + "_diagnostic_report.xlsx"); + + StringWriter sw = new StringWriter(); + Workbook workbook = null; + Sheet sheet = null; + workbook = new XSSFWorkbook(); + sheet = workbook.createSheet("Diagnostic Report"); + + Row header = sheet.createRow(0); + + CellStyle headerStyle = workbook.createCellStyle(); + XSSFFont font = ((XSSFWorkbook) workbook).createFont(); + font.setFontName("Calibri"); + font.setFontHeightInPoints((short) 11); + font.setBold(true); + headerStyle.setFont(font); + + Cell headerCell = header.createCell(0); + headerCell.setCellValue("tid"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(1); + headerCell.setCellValue("terminal_sn"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(2); + headerCell.setCellValue("merchant_type"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(3); + headerCell.setCellValue("vendor_name"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(4); + headerCell.setCellValue("diagnostic_date"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(5); + headerCell.setCellValue("create_ts"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(6); + headerCell.setCellValue("created_by"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(7); + headerCell.setCellValue("battery_temp"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(8); + headerCell.setCellValue("battery_percentage"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(9); + headerCell.setCellValue("latitude"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(10); + headerCell.setCellValue("longitude"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(11); + headerCell.setCellValue("meid"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(12); + headerCell.setCellValue("switching_times"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(13); + headerCell.setCellValue("swiping_card_times"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(14); + headerCell.setCellValue("dip_inserting_times"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(15); + headerCell.setCellValue("nfc_card_reading_times"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(16); + headerCell.setCellValue("front_camera_open_times"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(17); + headerCell.setCellValue("rear_camera_open_times"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(18); + headerCell.setCellValue("charge_times"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(19); + headerCell.setCellValue("total_memory"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(20); + headerCell.setCellValue("available_memory"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(21); + headerCell.setCellValue("total_flash_memory"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(22); + headerCell.setCellValue("available_flash_memory"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(23); + headerCell.setCellValue("total_mobile_data"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(24); + headerCell.setCellValue("current_boot_time"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(25); + headerCell.setCellValue("total_boot_time"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(26); + headerCell.setCellValue("total_length_printed"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(27); + headerCell.setCellValue("sam_available"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(28); + headerCell.setCellValue("android_os_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(29); + headerCell.setCellValue("android_kernel_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(30); + headerCell.setCellValue("rom_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(31); + headerCell.setCellValue("firmware_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(32); + headerCell.setCellValue("hardware_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(33); + headerCell.setCellValue("sp_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(34); + headerCell.setCellValue("vf_service_version"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(35); + headerCell.setCellValue("vrk_sn"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(36); + headerCell.setCellValue("cell_infos"); + headerCell.setCellStyle(headerStyle); + + headerCell = header.createCell(37); + headerCell.setCellValue("installed_apps"); + headerCell.setCellStyle(headerStyle); + + CellStyle detailStyle = null; + // reusable - detail style : that's why defined here + detailStyle = workbook.createCellStyle(); + CreationHelper createHelper = workbook.getCreationHelper(); + detailStyle.setDataFormat( + createHelper.createDataFormat().getFormat("yyyy-mm-dd hh:mm:ss")); + XSSFFont detailFont = ((XSSFWorkbook) workbook).createFont(); + detailFont.setFontName("Calibri"); + detailFont.setFontHeightInPoints((short) 11); + detailStyle.setFont(detailFont); + + // query + Transaction tx = persistence.createTransaction(); + try { + Query query = persistence.getEntityManager().createNativeQuery( + "SELECT tid, terminal_sn, merchant_type, vendor_name, diagnostic_date, create_ts, created_by, " + + "battery_temp, battery_percentage, latitude, longitude, meid, switching_times, " + + "swiping_card_times, dip_inserting_times, nfc_card_reading_times, front_camera_open_times, " + + "rear_camera_open_times, charge_times, total_memory, available_memory, total_flash_memory, " + + "available_flash_memory, total_mobile_data, current_boot_time, total_boot_time, total_length_printed, " + + "sam_available, android_os_version, android_kernel_version, rom_version, firmware_version, " + + "hardware_version, sp_version, vf_service_version, vrk_sn, " + + "cell_infos, installed_apps " + + "FROM public.tms_v_terminal_diagnostic_info " + + "WHERE diagnostic_date=? and upper(vendor_name)=upper(?)"); + query.setParameter(1, date); + query.setParameter(2, vendorName); + List list = query.getResultList(); + int rowNum = 0; + + for (Iterator it = list.iterator(); it.hasNext(); ) { + Object[] row = (Object[]) it.next(); + + Row detail = sheet.createRow(rowNum + 1); + Cell detailCell; + + // 0 - tid (String) + detailCell = detail.createCell(0); + detailCell.setCellValue(row[0] != null ? row[0].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 1 - terminal_sn (String) + detailCell = detail.createCell(1); + detailCell.setCellValue(row[1] != null ? row[1].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 2 - merchant_type (String) + detailCell = detail.createCell(2); + detailCell.setCellValue(row[2] != null ? row[2].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 3 - vendor_name (String) + detailCell = detail.createCell(3); + detailCell.setCellValue(row[3] != null ? row[3].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 4 - diagnostic_date (Timestamp/Date) + detailCell = detail.createCell(4); + detailCell.setCellValue((Date) row[4]); + detailCell.setCellStyle(detailStyle); + + // 5 - create_ts (Timestamp) + detailCell = detail.createCell(5); + detailCell.setCellValue(normalizeTimestamp((Timestamp) row[5])); + detailCell.setCellStyle(detailStyle); + + // 6 - created_by (String) + detailCell = detail.createCell(6); + detailCell.setCellValue(row[6] != null ? row[6].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 7 - battery_temp (Double) + detailCell = detail.createCell(7); + detailCell.setCellValue(normalizeDouble((Double) row[7])); + detailCell.setCellStyle(detailStyle); + + // 8 - battery_percentage (Integer) + detailCell = detail.createCell(8); + detailCell.setCellValue(normalizeInteger((Integer) row[8])); + detailCell.setCellStyle(detailStyle); + + // 9 - latitude (Double) + detailCell = detail.createCell(9); + detailCell.setCellValue(normalizeDouble((Double) row[9])); + detailCell.setCellStyle(detailStyle); + + // 10 - longitude (Double) + detailCell = detail.createCell(10); + detailCell.setCellValue(normalizeDouble((Double) row[10])); + detailCell.setCellStyle(detailStyle); + + // 11 - meid (String) + detailCell = detail.createCell(11); + detailCell.setCellValue(row[11] != null ? row[11].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 12 - switching_times (Integer) + detailCell = detail.createCell(12); + detailCell.setCellValue(normalizeInteger((Integer) row[12])); + detailCell.setCellStyle(detailStyle); + + // 13 - swiping_card_times (Integer) + detailCell = detail.createCell(13); + detailCell.setCellValue(normalizeInteger((Integer) row[13])); + detailCell.setCellStyle(detailStyle); + + // 14 - dip_inserting_times (Integer) + detailCell = detail.createCell(14); + detailCell.setCellValue(normalizeInteger((Integer) row[14])); + detailCell.setCellStyle(detailStyle); + + // 15 - nfc_card_reading_times (Integer) + detailCell = detail.createCell(15); + detailCell.setCellValue(normalizeInteger((Integer) row[15])); + detailCell.setCellStyle(detailStyle); + + // 16 - front_camera_open_times (Integer) + detailCell = detail.createCell(16); + detailCell.setCellValue(normalizeInteger((Integer) row[16])); + detailCell.setCellStyle(detailStyle); + + // 17 - rear_camera_open_times (Integer) + detailCell = detail.createCell(17); + detailCell.setCellValue(normalizeInteger((Integer) row[17])); + detailCell.setCellStyle(detailStyle); + + // 18 - charge_times (Integer) + detailCell = detail.createCell(18); + detailCell.setCellValue(normalizeInteger((Integer) row[18])); + detailCell.setCellStyle(detailStyle); + + // 19 - total_memory (Integer/Long) + detailCell = detail.createCell(19); + detailCell.setCellValue(normalizeLong((Long) row[19])); + detailCell.setCellStyle(detailStyle); + + // 20 - available_memory + detailCell = detail.createCell(20); + detailCell.setCellValue(normalizeLong((Long) row[20])); + detailCell.setCellStyle(detailStyle); + + // 21 - total_flash_memory + detailCell = detail.createCell(21); + detailCell.setCellValue(normalizeLong((Long) row[21])); + detailCell.setCellStyle(detailStyle); + + // 22 - available_flash_memory + detailCell = detail.createCell(22); + detailCell.setCellValue(normalizeLong((Long) row[22])); + detailCell.setCellStyle(detailStyle); + + // 23 - total_mobile_data (Double) + detailCell = detail.createCell(23); + detailCell.setCellValue(normalizeLong((Long) row[23])); + detailCell.setCellStyle(detailStyle); + + // 24 - current_boot_time (Integer) + detailCell = detail.createCell(24); + detailCell.setCellValue(normalizeInteger((Integer) row[24])); + detailCell.setCellStyle(detailStyle); + + // 25 - total_boot_time (Integer) + detailCell = detail.createCell(25); + detailCell.setCellValue(normalizeInteger((Integer) row[25])); + detailCell.setCellStyle(detailStyle); + + // 26 - total_length_printed (Double) + detailCell = detail.createCell(26); + detailCell.setCellValue(normalizeDouble((Double) row[26])); + detailCell.setCellStyle(detailStyle); + + // 27 - sam_available (Boolean) + detailCell = detail.createCell(27); + detailCell.setCellValue(normalizeBoolean((Boolean) row[27])); + detailCell.setCellStyle(detailStyle); + + // 28 - android_os_version (String) + detailCell = detail.createCell(28); + detailCell.setCellValue(row[28] != null ? row[28].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 29 - android_kernel_version + detailCell = detail.createCell(29); + detailCell.setCellValue(row[29] != null ? row[29].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 30 - rom_version + detailCell = detail.createCell(30); + detailCell.setCellValue(row[30] != null ? row[30].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 31 - firmware_version + detailCell = detail.createCell(31); + detailCell.setCellValue(row[31] != null ? row[31].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 32 - hardware_version + detailCell = detail.createCell(32); + detailCell.setCellValue(row[32] != null ? row[32].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 33 - sp_version + detailCell = detail.createCell(33); + detailCell.setCellValue(row[33] != null ? row[33].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 34 - vf_service_version + detailCell = detail.createCell(34); + detailCell.setCellValue(row[34] != null ? row[34].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 35 - vrk_sn + detailCell = detail.createCell(35); + detailCell.setCellValue(row[35] != null ? row[35].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 36 - cell_infos + detailCell = detail.createCell(36); + detailCell.setCellValue(row[36] != null ? row[36].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 37 - installed_apps + detailCell = detail.createCell(37); + detailCell.setCellValue(row[37] != null ? row[37].toString() : ""); + detailCell.setCellStyle(detailStyle); + + rowNum++; + } + } finally { + tx.end(); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + workbook.write(baos); + workbook.close(); + + report.setFileContent(baos.toByteArray()); + + // upload file + // ✅ Create FileDescriptor + FileDescriptor fd = dataManager.create(FileDescriptor.class); + fd.setName(dateTimeFormat.format(new Date()) + "_" + vendorName.toUpperCase() + "_Diagnostic_Report.xlsx"); + fd.setExtension("xlsx"); + fd.setSize((long) report.getFileContent().length); + fd.setCreateDate(new Date()); + + dataManager.commit(fd); + + // ✅ Save file to storage + fileStorageAPI.saveStream(fd, new ByteArrayInputStream(report.getFileContent())); + + FileDownloadWrapper fileDownloadWrapper = fileService.uploadFileToRemote(fd, true); + + result.setResponseCode("0000"); + result.setResponseDesc("Success"); + result.setData(fileDownloadWrapper); + } catch(Exception ex) { + result.setResponseCode("9999"); + result.setResponseDesc("Error generate diagnostic report: " + ex.getMessage()); + } finally { + } + return result; + } + + @Override + public BaseDetailResult exportLastHeartBeatReport(String vendorName, Date date) throws Exception { + logger.info("exportLastHeartBeatReport[" + vendorName + ", " + date + "]"); + BaseDetailResult result = new BaseDetailResult<>(); + ExportReportBean report = new ExportReportBean(); + + try { + report.setFilename(dateFormat.format(new Date()) + "_last_heartbeat_report.xlsx"); + + // ✅ Use streaming workbook (important for large data) + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("Last Heartbeat Report"); + + // ================= HEADER ================= + Row header = sheet.createRow(0); + + CellStyle headerStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontName("Calibri"); + font.setFontHeightInPoints((short) 11); + font.setBold(true); + headerStyle.setFont(font); + + String[] headers = { + "tid", + "terminal_sn", + "vendor_name", + "create_ts", + "created_by", + "battery_temp", + "battery_percentage", + "latitude", + "longitude", + "cell_type", + "cell_name", + "cell_strength", + "wifi_name", + "wifi_strength" + }; + + for (int i = 0; i < headers.length; i++) { + Cell headerCell = header.createCell(i); + headerCell.setCellValue(headers[i]); + headerCell.setCellStyle(headerStyle); + } + + // ================= DETAIL STYLE ================= + CellStyle detailStyle = workbook.createCellStyle(); + CreationHelper createHelper = workbook.getCreationHelper(); + detailStyle.setDataFormat( + createHelper.createDataFormat().getFormat("yyyy-mm-dd hh:mm:ss")); + + Font detailFont = workbook.createFont(); + detailFont.setFontName("Calibri"); + detailFont.setFontHeightInPoints((short) 11); + detailStyle.setFont(detailFont); + + // ================= DATE RANGE ================= + Date startDate = org.apache.commons.lang3.time.DateUtils.truncate(date, Calendar.DAY_OF_MONTH); + Date endDate = org.apache.commons.lang3.time.DateUtils.addSeconds( + org.apache.commons.lang3.time.DateUtils.addDays(startDate, 1), -1); + + // ================= QUERY ================= + Transaction tx = persistence.createTransaction(); + try { + Query query = persistence.getEntityManager().createNativeQuery( + "SELECT " + + "tte.terminal_id, " + // 0 + "terminal.sn, " + // 1 + "tte.vendor_name, " + // 2 + "thb.create_ts, " + // 3 + "terminal.sn, " + // 4 + "thb.battery_temp, " + // 5 + "thb.battery_percentage, " + // 6 + "thb.latitude, " + // 7 + "thb.longitude, " + // 8 + "thb.cell_infos " + // 9 + "FROM tms_terminal terminal " + + "JOIN tms_terminal_link link ON link.terminal_id = terminal.id " + + "JOIN tmsext_terminal_ext tte ON link.terminal_ext_id = tte.id AND tte.delete_ts IS NULL " + + "JOIN tms_device_profile profile ON terminal.profile_id = profile.id " + + "JOIN ( " + + " SELECT terminal_id, MAX(create_ts) AS max_ts " + + " FROM tms_heart_beat " + + " WHERE create_ts BETWEEN ?1 AND ?2 " + + " GROUP BY terminal_id " + + ") latest ON latest.terminal_id = terminal.id " + + "JOIN tms_heart_beat thb ON thb.terminal_id = latest.terminal_id AND thb.create_ts = latest.max_ts " + + "WHERE terminal.delete_ts IS NULL " + + "AND UPPER(tte.vendor_name) = UPPER(?3)" + ); + + query.setParameter(1, startDate); + query.setParameter(2, endDate); + query.setParameter(3, vendorName); + + List list = query.getResultList(); + int rowNum = 0; + + Gson gson = new Gson(); + for (Iterator it = list.iterator(); it.hasNext(); ) { + Object[] row = (Object[]) it.next(); + + Row detail = sheet.createRow(rowNum + 1); + Cell detailCell; + + // 0 - tid + detailCell = detail.createCell(0); + detailCell.setCellValue(row[0] != null ? row[0].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 1 - terminal_sn + detailCell = detail.createCell(1); + detailCell.setCellValue(row[1] != null ? row[1].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 2 - vendor_name + detailCell = detail.createCell(2); + detailCell.setCellValue(row[2] != null ? row[2].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 3 - create_ts + detailCell = detail.createCell(3); + detailCell.setCellValue(normalizeTimestamp((Timestamp) row[3])); + detailCell.setCellStyle(detailStyle); + + // 4 - created_by + detailCell = detail.createCell(4); + detailCell.setCellValue(row[4] != null ? row[4].toString() : ""); + detailCell.setCellStyle(detailStyle); + + // 5 - battery_temp + detailCell = detail.createCell(5); + detailCell.setCellValue(normalizeDouble((Double) row[5])); + detailCell.setCellStyle(detailStyle); + + // 6 - battery_percentage + detailCell = detail.createCell(6); + detailCell.setCellValue(normalizeInteger((Integer) row[6])); + detailCell.setCellStyle(detailStyle); + + // 7 - latitude + detailCell = detail.createCell(7); + detailCell.setCellValue(normalizeDouble((Double) row[7])); + detailCell.setCellStyle(detailStyle); + + // 8 - longitude + detailCell = detail.createCell(8); + detailCell.setCellValue(normalizeDouble((Double) row[8])); + detailCell.setCellStyle(detailStyle); + + // 9-13 - cell_infos + String cellInfosString = row[9] != null ? row[9].toString() : "{}"; + Type type = new TypeToken>() {}.getType(); + List cellInfos = gson.fromJson(cellInfosString, type); + String cellType = null; + String cellName = null; + Integer cellStrength = null; + String wifiName = null; + Integer wifiStrength = null; + if(cellInfos != null && !cellInfos.isEmpty()) { + // set cell info + for(CellInfo cellInfo : cellInfos) { + if("wifi".equals(cellInfo.getType())) { + wifiName = cellInfo.getName(); + wifiStrength = cellInfo.getStrength(); + } else { + cellType = cellInfo.getType(); + cellName = cellInfo.getName(); + cellStrength = cellInfo.getStrength(); + } + } + } + + // 9 - cell type + detailCell = detail.createCell(9); + detailCell.setCellValue(cellType); + detailCell.setCellStyle(detailStyle); + + // 10 - cell name + detailCell = detail.createCell(10); + detailCell.setCellValue(cellName); + detailCell.setCellStyle(detailStyle); + + // 11 - cell strength + detailCell = detail.createCell(11); + detailCell.setCellValue(normalizeInteger(cellStrength)); + detailCell.setCellStyle(detailStyle); + + // 12 - wifi name + detailCell = detail.createCell(12); + detailCell.setCellValue(wifiName); + detailCell.setCellStyle(detailStyle); + + // 13 - wifi strength + detailCell = detail.createCell(13); + detailCell.setCellValue(normalizeInteger(wifiStrength)); + detailCell.setCellStyle(detailStyle); + + rowNum++; + } + + } finally { + tx.end(); + } + + // ================= WRITE FILE ================= + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + workbook.write(baos); + workbook.close(); + + report.setFileContent(baos.toByteArray()); + + // ================= SAVE FILE ================= + FileDescriptor fd = dataManager.create(FileDescriptor.class); + fd.setName(dateTimeFormat.format(new Date()) + "_" + vendorName.toUpperCase() + "_Last_HeartBeat_Report.xlsx"); + fd.setExtension("xlsx"); + fd.setSize((long) report.getFileContent().length); + fd.setCreateDate(new Date()); + + dataManager.commit(fd); + + fileStorageAPI.saveStream(fd, new ByteArrayInputStream(report.getFileContent())); + + FileDownloadWrapper fileDownloadWrapper = fileService.uploadFileToRemote(fd, true); + + result.setResponseCode("0000"); + result.setResponseDesc("Success"); + result.setData(fileDownloadWrapper); + + } catch (Exception ex) { + logger.error("Error exportLastHeartBeatReport", ex); + result.setResponseCode("9999"); + result.setResponseDesc("Error generate last heartbeat report: " + ex.getMessage()); + } + + return result; + } + + /** + * Export MID Location Report + * @return + * @throws Exception + */ + public ExportReportBean exportReportMidLocationReport() throws Exception { + ExportReportBean report = new ExportReportBean(); + try { + boolean includeZero = reportConfig.getMidReportIncludeZero(); + String vendorName = reportConfig.getMidReportVendorName(); + String filenamePattern = reportConfig.getMidReportFilenamePattern(); + String filename = filenamePattern; + filename = filename.replace("{VENDOR_NAME}", vendorName); + filename = filename.replace("{DATE}", shortDateFormat.format(new Date())); + + report.setFilename(filename); + + StringWriter sw = new StringWriter(); + sw.append("\"MID;longitude;latitude;Nama Vendor\"").append("\n"); + // query + Transaction tx = persistence.createTransaction(); + try { + StringBuilder querySb = new StringBuilder(); + querySb.append("select t0.merchant_id,t0.latitude,t0.longitude\n"); + querySb.append("from (\n"); + querySb.append("\tselect \n"); + querySb.append("\t lpad(trim(leading '0' from tte.merchant_id), 12, '0') merchant_id,\n"); + querySb.append("\t t0.latitude,\n"); + querySb.append("\t t0.longitude,\n"); + querySb.append("\t (row_number() over (partition by tte.merchant_id order by t0.create_ts desc)) as rank\n"); + querySb.append("\tfrom tms_terminal t\n"); + querySb.append("\t inner join tms_terminal_link ttl on ttl.terminal_id = t.id\n"); + querySb.append("\t inner join tmsext_terminal_ext tte on ttl.terminal_ext_id = tte.id\n"); + querySb.append("\t inner join (\n"); + querySb.append("\t select thb.terminal_id,thb.longitude,thb.latitude,thb.create_ts,thb.cell_infos,\n"); + querySb.append("\t row_number() over (partition by thb.terminal_id order by thb.create_ts desc) as rownumber\n"); + querySb.append("\t from tms_heart_beat thb\n"); + querySb.append("\t where thb.create_ts between (to_char(now() - interval '1 day','YYYY-MM-DD')||' 00:00:00.000+07:00')::timestamp\n"); + querySb.append("\t and (to_char(now() - interval '1 day','YYYY-MM-DD')||' 23:59:59.999+07:00')::timestamp\n"); + querySb.append("\t ) t0 on t0.rownumber=1 and t0.terminal_id=t.id\n"); + querySb.append("\twhere t.delete_ts is null and tte.delete_ts is null\n"); + if(!includeZero) { + querySb.append("\t and (t.latitude <> 0.0 and t.longitude <> 0.0)\n"); + } + // valid indonesia boundary + querySb.append("\t and (t.latitude >= -10.1718 and t.latitude <= 5.88969)\n"); + querySb.append("\t and (t.longitude >= 95.31644 and t.longitude <= 140.71813)\n"); + querySb.append(") t0 where t0.rank=1\n"); + querySb.append("order by t0.merchant_id;"); + Query query = persistence.getEntityManager().createNativeQuery( + querySb.toString()); + List list = query.getResultList(); + int rowNum = 0; + for (Iterator it = list.iterator(); it.hasNext(); ) { + Object[] row = (Object[]) it.next(); + + String merchantId = (String) row[0]; + Double latitude = (Double) row[1]; + Double longitude = (Double) row[2]; + + sw.append("\""); + sw.append(merchantId).append(";"); + sw.append(normalizeDouble(longitude)).append(";"); + sw.append(normalizeDouble(latitude)).append(";"); + sw.append(vendorName); + sw.append("\""); + sw.append("\n"); + + rowNum++; + } + } finally { + tx.end(); + } + report.setFileContent(sw.toString().getBytes()); + sw.close(); + + // write to file + String localPath = reportConfig.getMidReportLocalPath(); + FileOutputStream fos = null; + try { + logger.info("Write report to: {}", (localPath + filename)); + fos = new FileOutputStream(localPath + filename); + fos.write(report.getFileContent()); + fos.flush(); + fos.close(); + + report.setWritten(true); + } finally { + if(fos != null) { + fos.close(); + fos = null; + } + } + + // send using ftp + String ftpHost = reportConfig.getMidReportFtpHost(); + int ftpPort = reportConfig.getMidReportFtpPort(); + String username = reportConfig.getMidReportFtpUsername(); + String password = reportConfig.getMidReportFtpPassword(); + String remoteFilename = reportConfig.getMidReportFtpPath() + filename; + + logger.info("Try to send the report using ftp ..."); + FTPSClient ftpClient = new FTPSClient(); + StringWriter ftpLogStringWriter = new StringWriter(); + try { + ftpClient.addProtocolCommandListener(new PrintCommandListener( + new PrintWriter(ftpLogStringWriter), true)); + ftpClient.connect(ftpHost, ftpPort); + /** + * https://stackoverflow.com/questions/12492330/550-ssl-tls-required-on-the-data-channel-using-apache-commons-ftpsclient + * for issue: 522 SSL/TLS required on the data channel + */ + // Set protection buffer size + ftpClient.execPBSZ(0); + // Set data channel protection to private + ftpClient.execPROT("P"); + + boolean loggedIn = ftpClient.login(username, password); + if(loggedIn) { + // set passive mode + ftpClient.setFileType(FTP.BINARY_FILE_TYPE); + ftpClient.enterLocalPassiveMode(); + ByteArrayInputStream bais = new ByteArrayInputStream(report.getFileContent()); + ftpClient.storeFile(remoteFilename, bais); + report.setSent(true); + } else { + throw new RuntimeException("Failed to FTP login!"); + } + } finally { + if(ftpClient.isConnected()) { + ftpClient.disconnect(); + } + } + logger.info("Ftp Log:\n{}\n", ftpLogStringWriter.toString()); + logger.info("exportReportMidLocationReport: {}, {}, {}", report.getFilename(), report.isWritten(), report.isSent()); + } finally { + } + return report; + } + + private String normalizeBoolean(Boolean bool) { + return bool == null ? "" : String.valueOf(bool.booleanValue()); + } + + private String normalizeInteger(Integer value) { + return value == null ? null : String.valueOf(value.intValue()); + } + + private String normalizeLong(Long value) { + return value == null ? null : String.valueOf(value.longValue()); + } + + private String normalizeDouble(Double value) { + return value == null ? null : String.valueOf(value); + } + + private String wrap(String value) { + return value == null ? null : "\"" + value + "\""; + } + + private Date normalizeTimestamp(Timestamp ts) { + return ts == null ? null : new Date(ts.getTime()); + } + +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/ResponseCodeServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/ResponseCodeServiceBean.java new file mode 100644 index 0000000..fa89749 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/ResponseCodeServiceBean.java @@ -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 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 parseResponseCodeFromFile(FileDescriptor fd) throws Exception { + List list = 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 = 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 createAttributesToColumns() { + Map 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); + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/TerminalExtServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/TerminalExtServiceBean.java new file mode 100644 index 0000000..6344f0b --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/TerminalExtServiceBean.java @@ -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() { + @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() { + @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); + } + } + +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/TerminalGroupImporterServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/TerminalGroupImporterServiceBean.java new file mode 100644 index 0000000..0fef00a --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/TerminalGroupImporterServiceBean.java @@ -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 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 parseTerminalsFromFile(FileDescriptor fd) throws Exception { + List 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 parseTerminalsFromFileOptimized(FileDescriptor fd) throws Exception { + List 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 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 terminals) throws Exception { + { + metadata = AppBeans.get(Metadata.NAME); + terminalAttributesToColumns = createTerminalAttributesToColumns(); + + // read the values + firstDataRowIndex = 1; + + try { + List parsedTerminals = new ArrayList<>(); + Set 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 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 loadTerminalsBySN(Set serialNumbers) { + Map terminalsBySn = new HashMap<>(); + if (serialNumbers.isEmpty()) { + return terminalsBySn; + } + + List 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 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 batch = dataManager.loadList(loadContext); + for (Terminal terminal : batch) { + if (terminal.getSn() != null) { + terminalsBySn.put(terminal.getSn().toLowerCase(), terminal); + } + } + } + + return terminalsBySn; + } + + private List parseTerminalRows(Sheet sheet) throws Exception { + metadata = AppBeans.get(Metadata.NAME); + terminalAttributesToColumns = createTerminalAttributesToColumns(); + firstDataRowIndex = 1; + + List 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 parsedTerminals) { + if (parsedTerminals.isEmpty()) { + return; + } + + UUID importId = UUID.randomUUID(); + logger.info("Terminal group optimized import matching started. importId={}, rows={}", importId, parsedTerminals.size()); + Map wrappersByRowNo = new HashMap<>(); + Map> 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 parsedTerminals, + Map 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 wrappersByRowNo, + Map> 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> wrappersByTerminalId) { + if (wrappersByTerminalId.isEmpty()) { + return; + } + + List 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 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 terminals = dataManager.loadList(loadContext); + for (Terminal terminal : terminals) { + List 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 createTerminalAttributesToColumns() { + Map columns = new HashMap<>(); + + columns.put(TID, 0); + columns.put(SN, 1); + + return columns; + } + + protected boolean eofTerminal(Row row) throws ImportFileEofEvaluationException { + return eofByColumnNullValueTerminal(row, TID); + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/service/TerminalImporterServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/TerminalImporterServiceBean.java new file mode 100644 index 0000000..33ba48f --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/TerminalImporterServiceBean.java @@ -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 terminalAttributesToColumns; + protected Map 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> issuerCards = new HashMap<>(); + private Map issuerIds = new HashMap<>(); + private Map terminalTemplateCaches = new HashMap<>(); + + @Override + public TerminalImporterObjectWrapper parseTerminalsFromFile(FileDescriptor fd) throws Exception { + List 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 parseTerminalsFromEditFile(FileDescriptor fd) throws Exception { + List 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 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 oldCards = issuerCards.get(oldIssuerId); + List 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 parseTerminalsFromFile2(FileDescriptor fd) throws Exception { + List 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 parseProfilingItems(FileDescriptor fd) throws Exception { + List 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() { + @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 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 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 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 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 templateAcquirers = templateTerminal.getAcquirers(); + + // cache of issuer's cards + LoadContext loadContext = LoadContext.create(Card.class); + LoadContext 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 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 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 templateIssuers = _acquirer.getIssuers(); + List 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 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 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 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 oldCards = issuerCards.get(oldIssuerId); + List 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 createTerminalAttributesToColumns() { + Map 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 createEditTerminalAttributesToColumns() { + Map 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 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 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 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 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 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 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; + } + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/service/TerminalServiceBean.java b/modules/core/src/com/cmobile/unifiedtms/service/TerminalServiceBean.java new file mode 100644 index 0000000..1bebbe7 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/TerminalServiceBean.java @@ -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 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 features = new ArrayList<>(); + + List 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; + } +} \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/controllers/TerminalController.java b/modules/core/src/com/cmobile/unifiedtms/service/controllers/TerminalController.java new file mode 100644 index 0000000..9096d66 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/controllers/TerminalController.java @@ -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 getTerminal( + @PathVariable("tid") String tid + ) { + + LoadContext 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 features = new ArrayList<>(); + + List 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; + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/service/messages.properties b/modules/core/src/com/cmobile/unifiedtms/service/messages.properties new file mode 100644 index 0000000..ea99afe --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/messages.properties @@ -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 \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/service/messages_in_ID.properties b/modules/core/src/com/cmobile/unifiedtms/service/messages_in_ID.properties new file mode 100644 index 0000000..62b0a8d --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/service/messages_in_ID.properties @@ -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 \ No newline at end of file diff --git a/modules/core/src/com/cmobile/unifiedtms/spring.xml b/modules/core/src/com/cmobile/unifiedtms/spring.xml new file mode 100644 index 0000000..c9a84e7 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/spring.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/modules/core/src/com/cmobile/unifiedtms/utils/ISOUtil.java b/modules/core/src/com/cmobile/unifiedtms/utils/ISOUtil.java new file mode 100644 index 0000000..1b3a699 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/utils/ISOUtil.java @@ -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(); + } + +} diff --git a/modules/core/src/com/cmobile/unifiedtms/utils/TerminalUpdateCache.java b/modules/core/src/com/cmobile/unifiedtms/utils/TerminalUpdateCache.java new file mode 100644 index 0000000..02cfbf1 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/utils/TerminalUpdateCache.java @@ -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 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> 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> 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 getCaches() { + return caches; + } + + public AtomicInteger getCurrentCapacity() { + return currentCapacity; + } +} diff --git a/modules/core/src/com/cmobile/unifiedtms/utils/XlsHelper.java b/modules/core/src/com/cmobile/unifiedtms/utils/XlsHelper.java new file mode 100644 index 0000000..87db1d0 --- /dev/null +++ b/modules/core/src/com/cmobile/unifiedtms/utils/XlsHelper.java @@ -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 getParameterValue(Map values, String parameter) { + if (values.get(parameter) == null) { + return null; + } + + return (T) values.get(parameter); + } + + @Nullable + public static Double getParameterDoubleValue(Map values, String parameter) { + if (values.get(parameter) == null) { + return null; + } + + return Double.valueOf(values.get(parameter).toString()); + } + + @Nullable + public static Integer getParameterIntegerValue(Map 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 values, String parameter) { + if (values.get(parameter) == null) { + return null; + } + + return values.get(parameter).toString().trim(); + } + +} \ No newline at end of file diff --git a/modules/core/src/sasc/emv/EMVTags.java b/modules/core/src/sasc/emv/EMVTags.java new file mode 100644 index 0000000..9b0ebc2 --- /dev/null +++ b/modules/core/src/sasc/emv/EMVTags.java @@ -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> issuerToTagsMap = new LinkedHashMap(); + private static LinkedHashMap> paymentSystemToTagsMap = new LinkedHashMap(); + + private static LinkedHashMap 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 Issuer’s 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 authority’s 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", "1–4 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 issuer’s 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 issuer’s 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 issuer’s 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 issuer’s 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 authority’s 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", "1–4 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 1–4 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 issuerTags = (LinkedHashMap) issuerToTagsMap.get(iin); + if (issuerTags == null) { + issuerTags = new LinkedHashMap(); + 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 paymentSystemTags = (LinkedHashMap) paymentSystemToTagsMap.get(ridBytesWrapped); + if (paymentSystemTags == null) { + paymentSystemTags = new LinkedHashMap(); + 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"); + } +} diff --git a/modules/core/src/sasc/emv/IssuerIdentificationNumber.java b/modules/core/src/sasc/emv/IssuerIdentificationNumber.java new file mode 100644 index 0000000..fbea981 --- /dev/null +++ b/modules/core/src/sasc/emv/IssuerIdentificationNumber.java @@ -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); + } +} diff --git a/modules/core/src/sasc/iso7816/BERTLV.java b/modules/core/src/sasc/iso7816/BERTLV.java new file mode 100644 index 0000000..a66b5ec --- /dev/null +++ b/modules/core/src/sasc/iso7816/BERTLV.java @@ -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 {} +} diff --git a/modules/core/src/sasc/iso7816/SmartCardException.java b/modules/core/src/sasc/iso7816/SmartCardException.java new file mode 100644 index 0000000..b67c11d --- /dev/null +++ b/modules/core/src/sasc/iso7816/SmartCardException.java @@ -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); } +} diff --git a/modules/core/src/sasc/iso7816/TLVException.java b/modules/core/src/sasc/iso7816/TLVException.java new file mode 100644 index 0000000..b190cde --- /dev/null +++ b/modules/core/src/sasc/iso7816/TLVException.java @@ -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); } +} diff --git a/modules/core/src/sasc/iso7816/TLVUtil.java b/modules/core/src/sasc/iso7816/TLVUtil.java new file mode 100644 index 0000000..59f3a42 --- /dev/null +++ b/modules/core/src/sasc/iso7816/TLVUtil.java @@ -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 parseTagAndLength(byte[] data) { + ByteArrayInputStream stream = new ByteArrayInputStream(data); + List tagAndLengthList = new ArrayList(); + + 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; + } +} diff --git a/modules/core/src/sasc/iso7816/Tag.java b/modules/core/src/sasc/iso7816/Tag.java new file mode 100644 index 0000000..e127671 --- /dev/null +++ b/modules/core/src/sasc/iso7816/Tag.java @@ -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; + } +} diff --git a/modules/core/src/sasc/iso7816/TagAndLength.java b/modules/core/src/sasc/iso7816/TagAndLength.java new file mode 100644 index 0000000..bfc8a1f --- /dev/null +++ b/modules/core/src/sasc/iso7816/TagAndLength.java @@ -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; } +} diff --git a/modules/core/src/sasc/iso7816/TagImpl.java b/modules/core/src/sasc/iso7816/TagImpl.java new file mode 100644 index 0000000..a895cfe --- /dev/null +++ b/modules/core/src/sasc/iso7816/TagImpl.java @@ -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); + } +} diff --git a/modules/core/src/sasc/iso7816/TagType.java b/modules/core/src/sasc/iso7816/TagType.java new file mode 100644 index 0000000..beb6908 --- /dev/null +++ b/modules/core/src/sasc/iso7816/TagType.java @@ -0,0 +1,6 @@ +package sasc.iso7816; + +public enum TagType { + PRIMITIVE, + CONSTRUCTED; +} diff --git a/modules/core/src/sasc/iso7816/TagValueType.java b/modules/core/src/sasc/iso7816/TagValueType.java new file mode 100644 index 0000000..338775a --- /dev/null +++ b/modules/core/src/sasc/iso7816/TagValueType.java @@ -0,0 +1,5 @@ +package sasc.iso7816; + +public enum TagValueType { + BINARY, NUMERIC, TEXT, MIXED, DOL, TEMPLATE; +} diff --git a/modules/core/src/sasc/util/ByteArrayWrapper.java b/modules/core/src/sasc/util/ByteArrayWrapper.java new file mode 100644 index 0000000..7c111e1 --- /dev/null +++ b/modules/core/src/sasc/util/ByteArrayWrapper.java @@ -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; + } +} diff --git a/modules/core/src/sasc/util/Util.java b/modules/core/src/sasc/util/Util.java new file mode 100644 index 0000000..4fc9163 --- /dev/null +++ b/modules/core/src/sasc/util/Util.java @@ -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))); + } +} diff --git a/modules/core/test/com/cmobile/unifiedtms/TmsTestContainer.java b/modules/core/test/com/cmobile/unifiedtms/TmsTestContainer.java new file mode 100644 index 0000000..00ca5ab --- /dev/null +++ b/modules/core/test/com/cmobile/unifiedtms/TmsTestContainer.java @@ -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 + } + + } +} \ No newline at end of file diff --git a/modules/core/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java b/modules/core/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java new file mode 100644 index 0000000..40187d8 --- /dev/null +++ b/modules/core/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java @@ -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 query = em.createQuery( + "select u from sec$User u where u.login = :userLogin", User.class); + query.setParameter("userLogin", "admin"); + List users = query.getResultList(); + tx.commit(); + Assertions.assertEquals(1, users.size()); + } + } +} \ No newline at end of file diff --git a/modules/core/test/com/cmobile/unifiedtms/test-app.properties b/modules/core/test/com/cmobile/unifiedtms/test-app.properties new file mode 100644 index 0000000..9d368fa --- /dev/null +++ b/modules/core/test/com/cmobile/unifiedtms/test-app.properties @@ -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 \ No newline at end of file diff --git a/modules/core/test/com/cmobile/unifiedtms/test-spring.xml b/modules/core/test/com/cmobile/unifiedtms/test-spring.xml new file mode 100644 index 0000000..dec5d53 --- /dev/null +++ b/modules/core/test/com/cmobile/unifiedtms/test-spring.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/modules/core/web/META-INF/context.xml b/modules/core/web/META-INF/context.xml new file mode 100644 index 0000000..f46ef2f --- /dev/null +++ b/modules/core/web/META-INF/context.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/modules/core/web/WEB-INF/web.xml b/modules/core/web/WEB-INF/web.xml new file mode 100644 index 0000000..e9e1b85 --- /dev/null +++ b/modules/core/web/WEB-INF/web.xml @@ -0,0 +1,38 @@ + + + + + + appPropertiesConfig + + classpath:com/cmobile/unifiedtms/app.properties + /WEB-INF/local.app.properties + "file:${app.home}/local.app.properties" + + + + + appComponents + 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 + + + com.haulmont.cuba.core.sys.AppContextLoader + + + + remoting + com.haulmont.cuba.core.sys.remoting.RemotingServlet + 1 + + + + remoting + /remoting/* + + + diff --git a/modules/global/src/com/cmobile/unifiedtms/app-component.xml b/modules/global/src/com/cmobile/unifiedtms/app-component.xml new file mode 100644 index 0000000..81340ec --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/app-component.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/config/BroadcastConfig.java b/modules/global/src/com/cmobile/unifiedtms/config/BroadcastConfig.java new file mode 100644 index 0000000..86db354 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/config/BroadcastConfig.java @@ -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 BroadcastConfig extends Config { + + @Property("broadcast.change-profile.req-id") + String getChangeProfileReqId(); + + void setChangeProfileReqId(String reqId); +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/config/ReportConfig.java b/modules/global/src/com/cmobile/unifiedtms/config/ReportConfig.java new file mode 100644 index 0000000..d465dfc --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/config/ReportConfig.java @@ -0,0 +1,48 @@ +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.DefaultBoolean; +import com.haulmont.cuba.core.config.defaults.DefaultInt; +import com.haulmont.cuba.core.config.defaults.DefaultString; +import com.haulmont.cuba.core.global.Secret; + +@Source(type = SourceType.DATABASE) +public interface ReportConfig extends Config { + + @Property("utms.report.mid.ftp.host") + String getMidReportFtpHost(); + + @Property("utms.report.mid.ftp.port") + @DefaultInt(21) + int getMidReportFtpPort(); + + @Property("utms.report.mid.ftp.username") + String getMidReportFtpUsername(); + + @Property("utms.report.mid.ftp.password") + @Secret + String getMidReportFtpPassword(); + + @Property("utms.report.mid.ftp.path") + @DefaultString("/") + String getMidReportFtpPath(); + + @Property("utms.report.mid.local.path") + String getMidReportLocalPath(); + + @Property("utms.report.mid.vendor.name") + @DefaultString("BIT") + String getMidReportVendorName(); + + @Property("utms.report.mid.filename.pattern") + @DefaultString("Lokasimerchant_{VENDOR_NAME}_{DATE}.csv") + String getMidReportFilenamePattern(); + + @Property("utms.report.mid.include-zero") + @DefaultBoolean(false) + Boolean getMidReportIncludeZero(); + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/Application.java b/modules/global/src/com/cmobile/unifiedtms/entity/Application.java new file mode 100644 index 0000000..2448853 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/Application.java @@ -0,0 +1,156 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.addon.sdbmt.entity.StandardTenantEntity; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.FileDescriptor; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.List; + +@NamePattern("%s|name") +@Table(name = "TMS_APPLICATION", indexes = { + @Index(name = "IDX_TMS_APPLICATION_UNQ", columnList = "PACKAGE_NAME, VERSION", unique = true) +}) +@Entity(name = "tms_Application") +public class Application extends StandardTenantEntity { + private static final long serialVersionUID = 1304409398139690797L; + + @NotNull + @Column(name = "PACKAGE_NAME", nullable = false) + protected String packageName; + + @NotNull + @Column(name = "COMPANY_NAME", nullable = false, length = 100) + protected String companyName; + + @NotNull + @Column(name = "NAME", nullable = false, length = 100) + protected String name; + + @Column(name = "DESCRIPTION") + protected String description; + + @NotNull + @Column(name = "APP_VERSION", nullable = false, length = 50) + protected String appVersion; + + @OnDeleteInverse(DeletePolicy.DENY) + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "ICON_ID") + protected FileDescriptor icon; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @OneToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "APK_ID") + protected FileDescriptor apk; + + @Column(name = "UNINSTALLABLE") + protected Boolean uninstallable; + + @JoinTable(name = "TMS_DOWNLOAD_TASK_APPLICATION_LINK", + joinColumns = @JoinColumn(name = "APPLICATION_ID"), + inverseJoinColumns = @JoinColumn(name = "DOWNLOAD_TASK_ID")) + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + protected List downloadTasks; + + @Column(name = "DOWNLOAD_URL", length = 500) + protected String downloadUrl; + + @Column(name = "CHECKSUM", length = 32) + protected String checksum; + + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } + + public String getDownloadUrl() { + return downloadUrl; + } + + public void setDownloadUrl(String downloadUrl) { + this.downloadUrl = downloadUrl; + } + + public List getDownloadTasks() { + return downloadTasks; + } + + public void setDownloadTasks(List downloadTasks) { + this.downloadTasks = downloadTasks; + } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public Boolean getUninstallable() { + return uninstallable; + } + + public void setUninstallable(Boolean uninstallable) { + this.uninstallable = uninstallable; + } + + public FileDescriptor getApk() { + return apk; + } + + public void setApk(FileDescriptor apk) { + this.apk = apk; + } + + public FileDescriptor getIcon() { + return icon; + } + + public void setIcon(FileDescriptor icon) { + this.icon = icon; + } + + public String getAppVersion() { + return appVersion; + } + + public void setAppVersion(String appVersion) { + this.appVersion = appVersion; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/ApplicationSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/ApplicationSimple.java new file mode 100644 index 0000000..1e30d7f --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/ApplicationSimple.java @@ -0,0 +1,106 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +@Table(name = "TMS_APPLICATION_SIMPLE") +@NamePattern("%s|appName") +@Entity(name = "tms_ApplicationSimple") +public class ApplicationSimple extends BaseUuidEntity implements Creatable { + private static final long serialVersionUID = -856427430430192794L; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @NotNull + @Column(name = "APP_NAME", nullable = false) + protected String appName; + + @NotNull + @Column(name = "PACKAGE_NAME", nullable = false) + protected String packageName; + + @NotNull + @Column(name = "APP_VERSION", nullable = false, length = 50) + protected String appVersion; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "DIAGNOSTIC_INFO_ID") + protected DiagnosticInfo diagnosticInfo; + + @JoinTable(name = "TMS_DELETE_TASK_APPLICATION_LINK", + joinColumns = @JoinColumn(name = "APPLICATION_ID"), + inverseJoinColumns = @JoinColumn(name = "DELETE_TASK_ID")) + @ManyToMany + protected List deleteTasks; + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public List getDeleteTasks() { + return deleteTasks; + } + + public void setDeleteTasks(List deleteTasks) { + this.deleteTasks = deleteTasks; + } + + public DiagnosticInfo getDiagnosticInfo() { + return diagnosticInfo; + } + + public void setDiagnosticInfo(DiagnosticInfo diagnosticInfo) { + this.diagnosticInfo = diagnosticInfo; + } + + public String getAppVersion() { + return appVersion; + } + + public void setAppVersion(String appVersion) { + this.appVersion = appVersion; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/City.java b/modules/global/src/com/cmobile/unifiedtms/entity/City.java new file mode 100644 index 0000000..3482cc9 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/City.java @@ -0,0 +1,44 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|name") +@Table(name = "TMS_CITY") +@Entity(name = "tms_City") +public class City extends StandardEntity { + private static final long serialVersionUID = 4686699293515578568L; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "STATES_ID") + protected States states; + + @NotNull + @Column(name = "NAME", nullable = false, length = 50) + protected String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public States getStates() { + return states; + } + + public void setStates(States states) { + this.states = states; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/ContactPerson.java b/modules/global/src/com/cmobile/unifiedtms/entity/ContactPerson.java new file mode 100644 index 0000000..8fe61a0 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/ContactPerson.java @@ -0,0 +1,93 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|name") +@Table(name = "TMS_CONTACT_PERSON") +@Entity(name = "tms_ContactPerson") +public class ContactPerson extends BaseUuidEntity implements Versioned { + private static final long serialVersionUID = -8558223710992415174L; + + @NotNull + @Column(name = "NAME", nullable = false, length = 100) + protected String name; + + @Column(name = "PHONE", length = 100) + protected String phone; + + @NotNull + @Column(name = "MOBILE", nullable = false, length = 100) + protected String mobile; + + @NotNull + @Column(name = "EMAIL", nullable = false) + protected String email; + + @OnDeleteInverse(DeletePolicy.CASCADE) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "MERCHANT_ID") + protected Merchant merchant; + + @Version + @Column(name = "VERSION", nullable = false) + protected Integer version; + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + public Merchant getMerchant() { + return merchant; + } + + public void setMerchant(Merchant merchant) { + this.merchant = merchant; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/Country.java b/modules/global/src/com/cmobile/unifiedtms/entity/Country.java new file mode 100644 index 0000000..c1681e2 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/Country.java @@ -0,0 +1,40 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|name") +@Table(name = "TMS_COUNTRY") +@Entity(name = "tms_Country") +public class Country extends StandardEntity { + private static final long serialVersionUID = 2184358567137236838L; + + @NotNull + @Column(name = "CODE", nullable = false, unique = true, length = 2) + protected String code; + + @NotNull + @Column(name = "NAME", nullable = false, length = 50) + protected String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DeleteTask.java b/modules/global/src/com/cmobile/unifiedtms/entity/DeleteTask.java new file mode 100644 index 0000000..4ce5a99 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DeleteTask.java @@ -0,0 +1,100 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.entity.enums.TaskStatus; +import com.haulmont.addon.sdbmt.entity.StandardTenantEntity; +import com.haulmont.chile.core.annotations.MetaProperty; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +@NamePattern("%s|name") +@Table(name = "TMS_DELETE_TASK") +@Entity(name = "tms_DeleteTask") +public class DeleteTask extends StandardTenantEntity { + private static final long serialVersionUID = -6504351468996643265L; + + @NotNull + @Column(name = "NAME", nullable = false, length = 50) + protected String name; + + @NotNull + @Column(name = "STATUS", nullable = false) + protected Integer status; + + @Column(name = "OLD_STATUS", nullable = true) + protected Integer oldStatus; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "DELETE_TIME") + protected Date deleteTime; + + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + @MetaProperty + @JoinTable(name = "TMS_DELETE_TASK_APPLICATION_SIMPLE_LINK", + joinColumns = @JoinColumn(name = "DELETE_TASK_ID"), + inverseJoinColumns = @JoinColumn(name = "APPLICATION_SIMPLE_ID")) + protected List applications; + + @JoinTable(name = "TMS_DELETE_TASK_TERMINAL_GROUP_LINK", + joinColumns = @JoinColumn(name = "DELETE_TASK_ID"), + inverseJoinColumns = @JoinColumn(name = "GROUP_ID")) + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + protected List terminalGroups; + + public void setApplications(List applications) { + this.applications = applications; + } + + public List getApplications() { + return applications; + } + + public TaskStatus getStatus() { + return status == null ? null : TaskStatus.fromId(status); + } + + public void setStatus(TaskStatus status) { + this.status = status == null ? null : status.getId(); + } + + public TaskStatus getOldStatus() { + return oldStatus == null ? null : TaskStatus.fromId(oldStatus); + } + + public void setOldStatus(TaskStatus oldStatus) { + this.oldStatus = oldStatus == null ? null : oldStatus.getId(); + } + + public List getTerminalGroups() { + return terminalGroups; + } + + public void setTerminalGroups(List terminalGroups) { + this.terminalGroups = terminalGroups; + } + + public Date getDeleteTime() { + return deleteTime; + } + + public void setDeleteTime(Date deleteTime) { + this.deleteTime = deleteTime; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DeleteTaskLog.java b/modules/global/src/com/cmobile/unifiedtms/entity/DeleteTaskLog.java new file mode 100644 index 0000000..400786e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DeleteTaskLog.java @@ -0,0 +1,171 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.entity.enums.DeleteTaskActivity; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.Updatable; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Table(name = "TMS_DELETE_TASK_LOG") +@Entity(name = "tms_DeleteTaskLog") +public class DeleteTaskLog extends BaseUuidEntity implements Creatable, Updatable, Versioned { + private static final long serialVersionUID = 4121894911005173586L; + + @NotNull + @OnDeleteInverse(DeletePolicy.CASCADE) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TASK_ID") + protected DeleteTask task; + + @NotNull + @OnDeleteInverse(DeletePolicy.CASCADE) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "APPLICATION_SIMPLE_ID") + protected ApplicationSimple application; + + @NotNull + @OnDeleteInverse(DeletePolicy.CASCADE) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TERMINAL_ID") + protected Terminal terminal; + + @NotNull + @Column(name = "ACTIVITY", nullable = false) + protected Integer activity; + + @Column(name = "OLD_ACTIVITY", nullable = true) + protected Integer oldActivity; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @Column(name = "UPDATE_TS") + protected Date updateTs; + + @Column(name = "UPDATED_BY", length = 50) + protected String updatedBy; + + @Version + @Column(name = "VERSION", nullable = false) + protected Integer version; + + @Column(name = "LAST_BROADCAST_TS") + protected Date lastBroadcastTs; + + @Column(name = "MESSAGE", nullable = true) + protected String message; + + public void setActivity(DeleteTaskActivity activity) { + this.activity = activity == null ? null : activity.getId(); + } + + public DeleteTaskActivity getActivity() { + return activity == null ? null : DeleteTaskActivity.fromId(activity); + } + + public void setOldActivity(DeleteTaskActivity oldActivity) { + this.oldActivity = oldActivity == null ? null : oldActivity.getId(); + } + + public DeleteTaskActivity getOldActivity() { + return oldActivity == null ? null : DeleteTaskActivity.fromId(oldActivity); + } + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public String getUpdatedBy() { + return updatedBy; + } + + @Override + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + @Override + public Date getUpdateTs() { + return updateTs; + } + + @Override + public void setUpdateTs(Date updateTs) { + this.updateTs = updateTs; + } + + public Date getLastBroadcastTs() { + return lastBroadcastTs; + } + + public void setLastBroadcastTs(Date lastBroadcastTs) { + this.lastBroadcastTs = lastBroadcastTs; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getCreateTs() { + return createTs; + } + + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public ApplicationSimple getApplication() { + return application; + } + + public void setApplication(ApplicationSimple application) { + this.application = application; + } + + public Terminal getTerminal() { + return terminal; + } + + public void setTerminal(Terminal terminal) { + this.terminal = terminal; + } + + public DeleteTask getTask() { + return task; + } + + public void setTask(DeleteTask task) { + this.task = task; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DeviceModel.java b/modules/global/src/com/cmobile/unifiedtms/entity/DeviceModel.java new file mode 100644 index 0000000..23a86fa --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DeviceModel.java @@ -0,0 +1,66 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.StandardEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Lob; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|model") +@Table(name = "TMS_DEVICE_MODEL") +@Entity(name = "tms_DeviceModel") +public class DeviceModel extends StandardEntity { + private static final long serialVersionUID = 5005483143510234743L; + + @NotNull + @Column(name = "MODEL", nullable = false, length = 50) + protected String model; + + @Lob + @Column(name = "MODEL_INFORMATION") + protected String modelInformation; + + @NotNull + @Column(name = "VENDOR_NAME", nullable = false, length = 100) + protected String vendorName; + + @NotNull + @Column(name = "VENDOR_COUNTRY", nullable = false, length = 50) + protected String vendorCountry; + + public String getModelInformation() { + return modelInformation; + } + + public void setModelInformation(String modelInformation) { + this.modelInformation = modelInformation; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getVendorCountry() { + return vendorCountry; + } + + public void setVendorCountry(String vendorCountry) { + this.vendorCountry = vendorCountry; + } + + public String getVendorName() { + return vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfile.java b/modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfile.java new file mode 100644 index 0000000..c04b87d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfile.java @@ -0,0 +1,303 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.ext.entity.Acquirer; +import com.haulmont.addon.sdbmt.entity.StandardTenantEntity; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.chile.core.annotations.NumberFormat; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +@NamePattern("%s|name") +@Table(name = "TMS_DEVICE_PROFILE") +@Entity(name = "tms_DeviceProfile") +public class DeviceProfile extends StandardTenantEntity { + private static final long serialVersionUID = 3648156946531995183L; + + @NotNull + @Column(name = "NAME", nullable = false, length = 50) + protected String name; + + @NotNull + @NumberFormat(pattern = "###,###") + @Column(name = "HEARTBEAT_INTERVAL", nullable = false) + protected Integer heartbeatInterval; + + @NumberFormat(pattern = "###,###") + @NotNull + @Column(name = "DIAGNOSTIC_INTERVAL", nullable = false) + protected Integer diagnosticInterval; + + @NotNull + @Column(name = "MASK_HOME_BUTTON", nullable = false) + protected Boolean maskHomeButton = false; + + @NotNull + @Column(name = "MASK_STATUS_BAR", nullable = false) + protected Boolean maskStatusBar = false; + + @NotNull + @Column(name = "SCHEDULE_REBOOT", nullable = false) + protected Boolean scheduleReboot = false; + + @Temporal(TemporalType.TIME) + @Column(name = "SCHEDULE_REBOOT_TIME") + protected Date scheduleRebootTime; + + @Column(name = "RELOCATION_ALERT") + protected Boolean relocationAlert; + + @NumberFormat(pattern = "###,###") + @Column(name = "MOVING_THRESHOLD") + protected Integer movingThreshold; + + @Column(name = "ADMIN_PASSWORD", length = 8) + protected String adminPassword; + + @Column(name = "IS_DEFAULT") + protected Boolean isDefault; + + @JoinTable(name = "TMS_DEVICE_PROFILE_ACQUIRER_LINK", + joinColumns = @JoinColumn(name = "DEVICE_PROFILE_ID"), + inverseJoinColumns = @JoinColumn(name = "ACQUIRER_ID")) + @OnDeleteInverse(DeletePolicy.DENY) + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + protected List acquirers; + + @Column(name = "FRONT_APP") + protected String frontApp; + + @OrderBy("packageName asc") + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.CASCADE) + @OneToMany(mappedBy = "profile") + protected List apps; + + @Column(name = "HOST_REPORT", nullable = true) + protected Boolean hostReport; + + @Column(name = "HOST_REPORT_TIMEOUT", nullable = true) + protected Integer hostReportTimeout; + + @Column(name = "HOST_REPORT_URL", nullable = true, length = 255) + protected String hostReportUrl; + + @Column(name = "HOST_REPORT_API_KEY", nullable = true, length = 64) + protected String hostReportApiKey; + + @Column(name = "HOST_LOGGING", nullable = true) + protected Boolean hostLogging; + + @Column(name = "HOST_LOGGING_TIMEOUT", nullable = true) + protected Integer hostLoggingTimeout; + + @Column(name = "HOST_LOGGING_URL", nullable = true, length = 255) + protected String hostLoggingUrl; + + @Column(name = "HOST_LOGGING_API_KEY", nullable = true, length = 64) + protected String hostLoggingApiKey; + + @Column(name = "HOST_LOGGING_INTERVAL", nullable = true) + protected Integer hostLoggingInterval; + + @Column(name = "AUTO_START_APP") + protected Boolean autoStartApp; + + public List getApps() { + return apps; + } + + public void setApps(List apps) { + this.apps = apps; + } + + public List getAcquirers() { + return acquirers; + } + + public void setAcquirers(List acquirers) { + this.acquirers = acquirers; + } + + public String getAdminPassword() { + return adminPassword; + } + + public void setAdminPassword(String adminPassword) { + this.adminPassword = adminPassword; + } + + public Boolean getIsDefault() { + return isDefault; + } + + public void setIsDefault(Boolean isDefault) { + this.isDefault = isDefault; + } + + public Date getScheduleRebootTime() { + return scheduleRebootTime; + } + + public void setScheduleRebootTime(Date scheduleRebootTime) { + this.scheduleRebootTime = scheduleRebootTime; + } + + public Boolean getScheduleReboot() { + return scheduleReboot; + } + + public void setScheduleReboot(Boolean scheduleReboot) { + this.scheduleReboot = scheduleReboot; + } + + public Boolean getMaskStatusBar() { + return maskStatusBar; + } + + public void setMaskStatusBar(Boolean maskStatusBar) { + this.maskStatusBar = maskStatusBar; + } + + public Boolean getMaskHomeButton() { + return maskHomeButton; + } + + public void setMaskHomeButton(Boolean maskHomeButton) { + this.maskHomeButton = maskHomeButton; + } + + public Integer getDiagnosticInterval() { + return diagnosticInterval; + } + + public void setDiagnosticInterval(Integer diagnosticInterval) { + this.diagnosticInterval = diagnosticInterval; + } + + public Integer getHeartbeatInterval() { + return heartbeatInterval; + } + + public void setHeartbeatInterval(Integer heartbeatInterval) { + this.heartbeatInterval = heartbeatInterval; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getMovingThreshold() { + return movingThreshold; + } + + public void setMovingThreshold(Integer movingThreshold) { + this.movingThreshold = movingThreshold; + } + + public Boolean getRelocationAlert() { + return relocationAlert; + } + + public void setRelocationAlert(Boolean relocationAlert) { + this.relocationAlert = relocationAlert; + } + + public String getFrontApp() { + return frontApp; + } + + public void setFrontApp(String frontApp) { + this.frontApp = frontApp; + } + + public Boolean getHostReport() { + return hostReport; + } + + public void setHostReport(Boolean hostReport) { + this.hostReport = hostReport; + } + + public Integer getHostReportTimeout() { + return hostReportTimeout; + } + + public void setHostReportTimeout(Integer hostReportTimeout) { + this.hostReportTimeout = hostReportTimeout; + } + + public String getHostReportUrl() { + return hostReportUrl; + } + + public void setHostReportUrl(String hostReportUrl) { + this.hostReportUrl = hostReportUrl; + } + + public String getHostReportApiKey() { + return hostReportApiKey; + } + + public void setHostReportApiKey(String hostReportApiKey) { + this.hostReportApiKey = hostReportApiKey; + } + + public Boolean getHostLogging() { + return hostLogging; + } + + public void setHostLogging(Boolean hostLogging) { + this.hostLogging = hostLogging; + } + + public Integer getHostLoggingTimeout() { + return hostLoggingTimeout; + } + + public void setHostLoggingTimeout(Integer hostLoggingTimeout) { + this.hostLoggingTimeout = hostLoggingTimeout; + } + + public String getHostLoggingUrl() { + return hostLoggingUrl; + } + + public void setHostLoggingUrl(String hostLoggingUrl) { + this.hostLoggingUrl = hostLoggingUrl; + } + + public String getHostLoggingApiKey() { + return hostLoggingApiKey; + } + + public void setHostLoggingApiKey(String hostLoggingApiKey) { + this.hostLoggingApiKey = hostLoggingApiKey; + } + + public Integer getHostLoggingInterval() { + return hostLoggingInterval; + } + + public void setHostLoggingInterval(Integer hostLoggingInterval) { + this.hostLoggingInterval = hostLoggingInterval; + } + + public Boolean getAutoStartApp() { + return autoStartApp; + } + + public void setAutoStartApp(Boolean autoStartApp) { + this.autoStartApp = autoStartApp; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfileApp.java b/modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfileApp.java new file mode 100644 index 0000000..e41d37e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DeviceProfileApp.java @@ -0,0 +1,45 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Table(name = "TMS_DEVICE_PROFILE_APP") +@NamePattern("%s|packageName") +@Entity(name = "tms_DeviceProfileApp") +public class DeviceProfileApp extends BaseUuidEntity { + private static final long serialVersionUID = -856427430430192794L; + + @NotNull + @Column(name = "PACKAGE_NAME", nullable = false) + protected String packageName; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @OnDelete(DeletePolicy.CASCADE) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "PROFILE_ID") + protected DeviceProfile profile; + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public DeviceProfile getProfile() { + return profile; + } + + public void setProfile(DeviceProfile profile) { + this.profile = profile; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfo.java b/modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfo.java new file mode 100644 index 0000000..59abb3d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfo.java @@ -0,0 +1,224 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import java.util.List; + +@Table(name = "TMS_DIAGNOSTIC_INFO") +@Entity(name = "tms_DiagnosticInfo") +public class DiagnosticInfo extends HeartBeat { + private static final long serialVersionUID = -5303253400862171364L; + + @Column(name = "MEID", length = 20) + protected String meid; + + @Lob + @Column(name = "INSTALLED_APPS_STRING") + protected String installedAppsString; + + @Column(name = "TOTAL_MEMORY") + protected Long totalMemory; + + @Column(name = "AVAILABLE_MEMORY") + protected Long availableMemory; + + @Column(name = "TOTAL_FLASH_MEMORY") + protected Long totalFlashMemory; + + @Column(name = "AVAILABLE_FLASH_MEMORY") + protected Long availableFlashMemory; + + @Column(name = "TOTAL_MOBILE_DATA") + protected Long totalMobileData; + + @Column(name = "SWITCHING_TIMES") + protected Integer switchingTimes; + + @Column(name = "CURRENT_BOOT_TIME") + protected Integer currentBootTime; + + @Column(name = "TOTAL_BOOT_TIME") + protected Integer totalBootTime; + + @Column(name = "TOTAL_LENGTH_PRINTED") + protected Double totalLengthPrinted; + + @Column(name = "SWIPING_CARD_TIMES") + protected Integer swipingCardTimes; + + @Column(name = "DIP_INSERTING_TIMES") + protected Integer dipInsertingTimes; + + @Column(name = "NFC_CARD_READING_TIMES") + protected Integer nfcCardReadingTimes; + + @Column(name = "FRONT_CAMERA_OPEN_TIMES") + protected Integer frontCameraOpenTimes; + + @Column(name = "REAR_CAMERA_OPEN_TIMES") + protected Integer rearCameraOpenTimes; + + @Column(name = "SAM_AVAILABLE") + protected Boolean samAvailable; + + @Column(name = "CHARGE_TIMES") + protected Integer chargeTimes; + + @OnDeleteInverse(DeletePolicy.DENY) + @OneToMany(mappedBy = "diagnosticInfo", cascade = CascadeType.PERSIST) + protected List installedApps; + + public void setTotalLengthPrinted(Double totalLengthPrinted) { + this.totalLengthPrinted = totalLengthPrinted; + } + + public Double getTotalLengthPrinted() { + return totalLengthPrinted; + } + + public String getInstalledAppsString() { + return installedAppsString; + } + + public void setInstalledAppsString(String installedAppsString) { + this.installedAppsString = installedAppsString; + } + + public void setInstalledApps(List installedApps) { + this.installedApps = installedApps; + } + + public List getInstalledApps() { + return installedApps; + } + + public void setTotalMemory(Long totalMemory) { + this.totalMemory = totalMemory; + } + + public Long getTotalMemory() { + return totalMemory; + } + + public void setAvailableMemory(Long availableMemory) { + this.availableMemory = availableMemory; + } + + public Long getAvailableMemory() { + return availableMemory; + } + + public void setTotalFlashMemory(Long totalFlashMemory) { + this.totalFlashMemory = totalFlashMemory; + } + + public Long getTotalFlashMemory() { + return totalFlashMemory; + } + + public void setAvailableFlashMemory(Long availableFlashMemory) { + this.availableFlashMemory = availableFlashMemory; + } + + public Long getAvailableFlashMemory() { + return availableFlashMemory; + } + + public void setTotalMobileData(Long totalMobileData) { + this.totalMobileData = totalMobileData; + } + + public Long getTotalMobileData() { + return totalMobileData; + } + + public void setCurrentBootTime(Integer currentBootTime) { + this.currentBootTime = currentBootTime; + } + + public Integer getCurrentBootTime() { + return currentBootTime; + } + + public void setTotalBootTime(Integer totalBootTime) { + this.totalBootTime = totalBootTime; + } + + public Integer getTotalBootTime() { + return totalBootTime; + } + + public Integer getChargeTimes() { + return chargeTimes; + } + + public void setChargeTimes(Integer chargeTimes) { + this.chargeTimes = chargeTimes; + } + + public Integer getRearCameraOpenTimes() { + return rearCameraOpenTimes; + } + + public void setRearCameraOpenTimes(Integer rearCameraOpenTimes) { + this.rearCameraOpenTimes = rearCameraOpenTimes; + } + + public Integer getFrontCameraOpenTimes() { + return frontCameraOpenTimes; + } + + public void setFrontCameraOpenTimes(Integer frontCameraOpenTimes) { + this.frontCameraOpenTimes = frontCameraOpenTimes; + } + + public Integer getNfcCardReadingTimes() { + return nfcCardReadingTimes; + } + + public void setNfcCardReadingTimes(Integer nfcCardReadingTimes) { + this.nfcCardReadingTimes = nfcCardReadingTimes; + } + + public Integer getDipInsertingTimes() { + return dipInsertingTimes; + } + + public void setDipInsertingTimes(Integer dipInsertingTimes) { + this.dipInsertingTimes = dipInsertingTimes; + } + + public Integer getSwipingCardTimes() { + return swipingCardTimes; + } + + public void setSwipingCardTimes(Integer swipingCardTimes) { + this.swipingCardTimes = swipingCardTimes; + } + + public Integer getSwitchingTimes() { + return switchingTimes; + } + + public void setSwitchingTimes(Integer switchingTimes) { + this.switchingTimes = switchingTimes; + } + + public String getMeid() { + return meid; + } + + public void setMeid(String meid) { + this.meid = meid; + } + + public Boolean getSamAvailable() { + return samAvailable; + } + + public void setSamAvailable(Boolean samAvailable) { + this.samAvailable = samAvailable; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfoReport.java b/modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfoReport.java new file mode 100644 index 0000000..8f0cffd --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DiagnosticInfoReport.java @@ -0,0 +1,419 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.global.DesignSupport; + +import javax.persistence.*; +import java.util.Date; +import java.util.UUID; + +@DesignSupport("{'dbView':true,'imported':true,'generateDdl':false}") +@NamePattern("%s|terminalId") +@Table(name = "tms_v_terminal_diagnostic_info") +@Entity(name = "tms_DiagnosticInfoReport") +public class DiagnosticInfoReport extends BaseUuidEntity implements Creatable { + private static final long serialVersionUID = 3273694768616434323L; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "create_ts") + protected Date createTs; + + @Column(name = "created_by", length = 50) + protected String createdBy; + + @Column(name = "available_flash_memory") + protected Long availableFlashMemory; + + @Column(name = "available_memory") + protected Long availableMemory; + + @Column(name = "battery_percentage") + protected Integer batteryPercentage; + + @Column(name = "battery_temp") + protected Double batteryTemp; + + @Column(name = "charge_times") + protected Integer chargeTimes; + + @Column(name = "current_boot_time") + protected Integer currentBootTime; + + @Column(name = "dip_inserting_times") + protected Integer dipInsertingTimes; + + @Column(name = "front_camera_open_times") + protected Integer frontCameraOpenTimes; + + @Column(name = "latitude") + protected Double latitude; + + @Column(name = "longitude") + protected Double longitude; + + @Column(name = "meid", length = 20) + protected String meid; + + @Column(name = "nfc_card_reading_times") + protected Integer nfcCardReadingTimes; + + @Column(name = "rear_camera_open_times") + protected Integer rearCameraOpenTimes; + + @Column(name = "swiping_card_times") + protected Integer swipingCardTimes; + + @Column(name = "switching_times") + protected Integer switchingTimes; + + @Column(name = "TERMINAL_EXT_ID") + protected UUID terminalExtId; + + @Column(name = "tid") + protected String tid; + + @Column(name = "terminal_sn", length = 30) + protected String terminalSn; + + @Column(name = "total_boot_time") + protected Integer totalBootTime; + + @Column(name = "total_flash_memory") + protected Long totalFlashMemory; + + @Column(name = "total_length_printed") + protected Double totalLengthPrinted; + + @Column(name = "total_memory") + protected Long totalMemory; + + @Column(name = "total_mobile_data") + protected Long totalMobileData; + + @Column(name = "sam_available") + protected Boolean samAvailable; + + @Column(name = "android_os_version") + protected String androidOSVersion; + + @Column(name = "android_kernel_version") + protected String androidKernelVersion; + + @Column(name = "rom_version") + protected String romVersion; + + @Column(name = "firmware_version") + protected String firmwareVersion; + + @Column(name = "hardware_version") + protected String hardwareVersion; + + @Column(name = "sp_version") + protected String spVersion; + + @Column(name = "vf_service_version") + protected String vfServiceVersion; + + @Column(name = "vrk_sn") + protected String vrkSn; + + @Column(name = "installed_apps") + protected String installedApps; + + @Column(name = "cell_infos") + protected String cellInfos; + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Long getAvailableFlashMemory() { + return availableFlashMemory; + } + + public void setAvailableFlashMemory(Long availableFlashMemory) { + this.availableFlashMemory = availableFlashMemory; + } + + public Long getAvailableMemory() { + return availableMemory; + } + + public void setAvailableMemory(Long availableMemory) { + this.availableMemory = availableMemory; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Integer getChargeTimes() { + return chargeTimes; + } + + public void setChargeTimes(Integer chargeTimes) { + this.chargeTimes = chargeTimes; + } + + public Integer getCurrentBootTime() { + return currentBootTime; + } + + public void setCurrentBootTime(Integer currentBootTime) { + this.currentBootTime = currentBootTime; + } + + public Integer getDipInsertingTimes() { + return dipInsertingTimes; + } + + public void setDipInsertingTimes(Integer dipInsertingTimes) { + this.dipInsertingTimes = dipInsertingTimes; + } + + public Integer getFrontCameraOpenTimes() { + return frontCameraOpenTimes; + } + + public void setFrontCameraOpenTimes(Integer frontCameraOpenTimes) { + this.frontCameraOpenTimes = frontCameraOpenTimes; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public String getMeid() { + return meid; + } + + public void setMeid(String meid) { + this.meid = meid; + } + + public Integer getNfcCardReadingTimes() { + return nfcCardReadingTimes; + } + + public void setNfcCardReadingTimes(Integer nfcCardReadingTimes) { + this.nfcCardReadingTimes = nfcCardReadingTimes; + } + + public Integer getRearCameraOpenTimes() { + return rearCameraOpenTimes; + } + + public void setRearCameraOpenTimes(Integer rearCameraOpenTimes) { + this.rearCameraOpenTimes = rearCameraOpenTimes; + } + + public Integer getSwipingCardTimes() { + return swipingCardTimes; + } + + public void setSwipingCardTimes(Integer swipingCardTimes) { + this.swipingCardTimes = swipingCardTimes; + } + + public Integer getSwitchingTimes() { + return switchingTimes; + } + + public void setSwitchingTimes(Integer switchingTimes) { + this.switchingTimes = switchingTimes; + } + + public String getTid() { + return tid; + } + + public void setTid(String tid) { + this.tid = tid; + } + + public UUID getTerminalExtId() { + return terminalExtId; + } + + public void setTerminalExtId(UUID terminalExtId) { + this.terminalExtId = terminalExtId; + } + + public String getTerminalSn() { + return terminalSn; + } + + public void setTerminalSn(String terminalSn) { + this.terminalSn = terminalSn; + } + + public Integer getTotalBootTime() { + return totalBootTime; + } + + public void setTotalBootTime(Integer totalBootTime) { + this.totalBootTime = totalBootTime; + } + + public Long getTotalFlashMemory() { + return totalFlashMemory; + } + + public void setTotalFlashMemory(Long totalFlashMemory) { + this.totalFlashMemory = totalFlashMemory; + } + + public Double getTotalLengthPrinted() { + return totalLengthPrinted; + } + + public void setTotalLengthPrinted(Double totalLengthPrinted) { + this.totalLengthPrinted = totalLengthPrinted; + } + + public Long getTotalMemory() { + return totalMemory; + } + + public void setTotalMemory(Long totalMemory) { + this.totalMemory = totalMemory; + } + + public Long getTotalMobileData() { + return totalMobileData; + } + + public void setTotalMobileData(Long totalMobileData) { + this.totalMobileData = totalMobileData; + } + + public Boolean getSamAvailable() { + return samAvailable; + } + + public void setSamAvailable(Boolean samAvailable) { + this.samAvailable = samAvailable; + } + + public String getAndroidOSVersion() { + return androidOSVersion; + } + + public void setAndroidOSVersion(String androidOSVersion) { + this.androidOSVersion = androidOSVersion; + } + + public String getAndroidKernelVersion() { + return androidKernelVersion; + } + + public void setAndroidKernelVersion(String androidKernelVersion) { + this.androidKernelVersion = androidKernelVersion; + } + + public String getRomVersion() { + return romVersion; + } + + public void setRomVersion(String romVersion) { + this.romVersion = romVersion; + } + + public String getFirmwareVersion() { + return firmwareVersion; + } + + public void setFirmwareVersion(String firmwareVersion) { + this.firmwareVersion = firmwareVersion; + } + + public String getHardwareVersion() { + return hardwareVersion; + } + + public void setHardwareVersion(String hardwareVersion) { + this.hardwareVersion = hardwareVersion; + } + + public String getSpVersion() { + return spVersion; + } + + public void setSpVersion(String spVersion) { + this.spVersion = spVersion; + } + + public String getVfServiceVersion() { + return vfServiceVersion; + } + + public void setVfServiceVersion(String vfServiceVersion) { + this.vfServiceVersion = vfServiceVersion; + } + + public String getVrkSn() { + return vrkSn; + } + + public void setVrkSn(String vrkSn) { + this.vrkSn = vrkSn; + } + + public String getInstalledApps() { + return installedApps; + } + + public void setInstalledApps(String installedApps) { + this.installedApps = installedApps; + } + + public String getCellInfos() { + return cellInfos; + } + + public void setCellInfos(String cellInfos) { + this.cellInfos = cellInfos; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/District.java b/modules/global/src/com/cmobile/unifiedtms/entity/District.java new file mode 100644 index 0000000..4360e93 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/District.java @@ -0,0 +1,44 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|name") +@Table(name = "TMS_DISTRICT") +@Entity(name = "tms_District") +public class District extends StandardEntity { + private static final long serialVersionUID = -1043079435144263046L; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "CITY_ID") + protected City city; + + @NotNull + @Column(name = "NAME", nullable = false, length = 50) + protected String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public City getCity() { + return city; + } + + public void setCity(City city) { + this.city = city; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DownloadTask.java b/modules/global/src/com/cmobile/unifiedtms/entity/DownloadTask.java new file mode 100644 index 0000000..e696d9e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DownloadTask.java @@ -0,0 +1,150 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.entity.enums.DownloadTimeType; +import com.cmobile.unifiedtms.entity.enums.InstallationTimeType; +import com.cmobile.unifiedtms.entity.enums.TaskNotificationType; +import com.cmobile.unifiedtms.entity.enums.TaskStatus; +import com.haulmont.addon.sdbmt.entity.StandardTenantEntity; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +@NamePattern("%s|name") +@Table(name = "TMS_DOWNLOAD_TASK") +@Entity(name = "tms_DownloadTask") +public class DownloadTask extends StandardTenantEntity { + private static final long serialVersionUID = -6504351468996643265L; + + @NotNull + @Column(name = "NAME", nullable = false, length = 50) + protected String name; + + @NotNull + @Column(name = "STATUS", nullable = false) + protected Integer status; + + @Column(name = "OLD_STATUS", nullable = true) + protected Integer oldStatus; + + @NotNull + @Column(name = "DOWNLOAD_TIME_TYPE", nullable = false) + protected Integer downloadTimeType; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "DOWNLOAD_TIME") + protected Date downloadTime; + + @NotNull + @Column(name = "INSTALLATION_TIME_TYPE", nullable = false) + protected Integer installationTimeType; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "INSTALLATION_TIME") + protected Date installationTime; + + @NotNull + @Column(name = "INSTALLATION_NOTIFICATION", nullable = false) + protected Integer installationNotification; + + @JoinTable(name = "TMS_DOWNLOAD_TASK_APPLICATION_LINK", + joinColumns = @JoinColumn(name = "DOWNLOAD_TASK_ID"), + inverseJoinColumns = @JoinColumn(name = "APPLICATION_ID")) + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + protected List applications; + + @JoinTable(name = "TMS_DOWNLOAD_TASK_TERMINAL_GROUP_LINK", + joinColumns = @JoinColumn(name = "DOWNLOAD_TASK_ID"), + inverseJoinColumns = @JoinColumn(name = "GROUP_ID")) + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + protected List terminalGroups; + + public TaskStatus getStatus() { + return status == null ? null : TaskStatus.fromId(status); + } + + public void setStatus(TaskStatus status) { + this.status = status == null ? null : status.getId(); + } + + public TaskStatus getOldStatus() { + return oldStatus == null ? null : TaskStatus.fromId(oldStatus); + } + + public void setOldStatus(TaskStatus oldStatus) { + this.oldStatus = oldStatus == null ? null : oldStatus.getId(); + } + + public List getApplications() { + return applications; + } + + public void setApplications(List applications) { + this.applications = applications; + } + + public List getTerminalGroups() { + return terminalGroups; + } + + public void setTerminalGroups(List terminalGroups) { + this.terminalGroups = terminalGroups; + } + + public TaskNotificationType getInstallationNotification() { + return installationNotification == null ? null : TaskNotificationType.fromId(installationNotification); + } + + public void setInstallationNotification(TaskNotificationType installationNotification) { + this.installationNotification = installationNotification == null ? null : installationNotification.getId(); + } + + public Date getInstallationTime() { + return installationTime; + } + + public void setInstallationTime(Date installationTime) { + this.installationTime = installationTime; + } + + public InstallationTimeType getInstallationTimeType() { + return installationTimeType == null ? null : InstallationTimeType.fromId(installationTimeType); + } + + public void setInstallationTimeType(InstallationTimeType installationTimeType) { + this.installationTimeType = installationTimeType == null ? null : installationTimeType.getId(); + } + + public Date getDownloadTime() { + return downloadTime; + } + + public void setDownloadTime(Date downloadTime) { + this.downloadTime = downloadTime; + } + + public DownloadTimeType getDownloadTimeType() { + return downloadTimeType == null ? null : DownloadTimeType.fromId(downloadTimeType); + } + + public void setDownloadTimeType(DownloadTimeType downloadTimeType) { + this.downloadTimeType = downloadTimeType == null ? null : downloadTimeType.getId(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/DownloadTaskLog.java b/modules/global/src/com/cmobile/unifiedtms/entity/DownloadTaskLog.java new file mode 100644 index 0000000..0338352 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/DownloadTaskLog.java @@ -0,0 +1,172 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.entity.enums.DownloadTaskActivity; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.Updatable; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Table(name = "TMS_DOWNLOAD_TASK_LOG") +@Entity(name = "tms_DownloadTaskLog") +public class DownloadTaskLog extends BaseUuidEntity implements Creatable, Updatable, Versioned { + private static final long serialVersionUID = 4115894911005173586L; + + @NotNull + @OnDeleteInverse(DeletePolicy.CASCADE) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TASK_ID") + protected DownloadTask task; + + @NotNull + @OnDeleteInverse(DeletePolicy.CASCADE) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "APPLICATION_ID") + protected Application application; + + @NotNull + @OnDeleteInverse(DeletePolicy.CASCADE) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TERMINAL_ID") + protected Terminal terminal; + + @NotNull + @Column(name = "ACTIVITY", nullable = false) + protected Integer activity; + + @Column(name = "OLD_ACTIVITY", nullable = true) + protected Integer oldActivity; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @Column(name = "UPDATE_TS") + protected Date updateTs; + + @Column(name = "UPDATED_BY", length = 50) + protected String updatedBy; + + @Version + @Column(name = "VERSION", nullable = false) + protected Integer version; + + @Column(name = "LAST_BROADCAST_TS") + protected Date lastBroadcastTs; + + @Column(name = "MESSAGE", nullable = true) + protected String message; + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public String getUpdatedBy() { + return updatedBy; + } + + @Override + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + @Override + public Date getUpdateTs() { + return updateTs; + } + + @Override + public void setUpdateTs(Date updateTs) { + this.updateTs = updateTs; + } + + public Date getLastBroadcastTs() { + return lastBroadcastTs; + } + + public void setLastBroadcastTs(Date lastBroadcastTs) { + this.lastBroadcastTs = lastBroadcastTs; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getCreateTs() { + return createTs; + } + + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public DownloadTaskActivity getActivity() { + return activity == null ? null : DownloadTaskActivity.fromId(activity); + } + + public void setActivity(DownloadTaskActivity activity) { + this.activity = activity == null ? null : activity.getId(); + } + + public DownloadTaskActivity getOldActivity() { + return oldActivity == null ? null : DownloadTaskActivity.fromId(oldActivity); + } + + public void setOldActivity(DownloadTaskActivity oldActivity) { + this.oldActivity = oldActivity == null ? null : oldActivity.getId(); + } + + public Application getApplication() { + return application; + } + + public void setApplication(Application application) { + this.application = application; + } + + public Terminal getTerminal() { + return terminal; + } + + public void setTerminal(Terminal terminal) { + this.terminal = terminal; + } + + public DownloadTask getTask() { + return task; + } + + public void setTask(DownloadTask task) { + this.task = task; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/ExportReportBean.java b/modules/global/src/com/cmobile/unifiedtms/entity/ExportReportBean.java new file mode 100644 index 0000000..414734d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/ExportReportBean.java @@ -0,0 +1,45 @@ +package com.cmobile.unifiedtms.entity; + +import java.io.Serializable; + +public class ExportReportBean implements Serializable { + + private String filename; + private byte[] fileContent; + private boolean written; + private boolean sent; + + public ExportReportBean() {} + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public byte[] getFileContent() { + return fileContent; + } + + public void setFileContent(byte[] fileContent) { + this.fileContent = fileContent; + } + + public boolean isWritten() { + return written; + } + + public void setWritten(boolean written) { + this.written = written; + } + + public boolean isSent() { + return sent; + } + + public void setSent(boolean sent) { + this.sent = sent; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/HeartBeat.java b/modules/global/src/com/cmobile/unifiedtms/entity/HeartBeat.java new file mode 100644 index 0000000..8d68512 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/HeartBeat.java @@ -0,0 +1,166 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.chile.core.annotations.NumberFormat; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@NamePattern("%s|terminal") +@Table(name = "TMS_HEART_BEAT") +@Entity(name = "tms_HeartBeat") +public class HeartBeat extends BaseUuidEntity implements Creatable, Versioned { + private static final long serialVersionUID = 6491584963030369358L; + + @NotNull + @OnDeleteInverse(DeletePolicy.CASCADE) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TERMINAL_ID") + protected Terminal terminal; + + @NumberFormat(pattern = "###.##") + @NotNull + @Column(name = "BATTERY_TEMP", nullable = false) + protected Double batteryTemp; + + @NotNull + @Column(name = "BATTERY_PERCENTAGE", nullable = false) + protected Integer batteryPercentage; + + @Column(name = "LATITUDE") + protected Double latitude; + + @Column(name = "LONGITUDE") + protected Double longitude; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @Version + @Column(name = "VERSION", nullable = false) + protected Integer version; + + @Override + public Integer getVersion() { + return version; + } + + @Column(name = "CELL_INFOS", length = 500, nullable = true) + protected String cellInfos; + + @Column(name = "CELL_NAME", length = 50, nullable = true) + protected String cellName; + + @Column(name = "CELL_TYPE", length = 10, nullable = true) + protected String cellType; + + @Column(name = "CELL_STRENGTH", nullable = true) + protected Integer cellStrength; + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Terminal getTerminal() { + return terminal; + } + + public void setTerminal(Terminal terminal) { + this.terminal = terminal; + } + + public String getCellInfos() { + return cellInfos; + } + + public void setCellInfos(String cellInfos) { + this.cellInfos = cellInfos; + } + + public String getCellName() { + return cellName; + } + + public void setCellName(String cellName) { + this.cellName = cellName; + } + + public String getCellType() { + return cellType; + } + + public void setCellType(String cellType) { + this.cellType = cellType; + } + + public Integer getCellStrength() { + return cellStrength; + } + + public void setCellStrength(Integer cellStrength) { + this.cellStrength = cellStrength; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/HeartbeatSummary.java b/modules/global/src/com/cmobile/unifiedtms/entity/HeartbeatSummary.java new file mode 100644 index 0000000..42bf23c --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/HeartbeatSummary.java @@ -0,0 +1,244 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.cuba.core.entity.BaseStringIdEntity; +import com.haulmont.cuba.core.entity.Updatable; +import com.haulmont.cuba.core.global.DesignSupport; + +import javax.persistence.*; +import java.util.Date; + +@DesignSupport("{'dbView':true,'imported':true,'generateDdl':false}") +@Table(name = "tms_v_terminal_hb_summary_report") +@Entity(name = "tms_HeartbeatSummary") +public class HeartbeatSummary extends BaseStringIdEntity implements Updatable { + private static final long serialVersionUID = -8873579277694377762L; + + @Id + @Column(name = "id", nullable = false, length = 36) + protected String id; + + @Column(name = "group_name", length = 100) + protected String groupName; + + @Column(name = "retail_total") + protected Integer retailTotal; + + @Column(name = "retail_total_1h") + protected Integer retailTotal1H; + + @Column(name = "retail_total_1d") + protected Integer retailTotal1D; + + @Column(name = "retail_total_today") + protected Integer retailTotalToday; + + @Column(name = "retail_total_7d") + protected Integer retailTotal7D; + + @Column(name = "retail_total_more_7d") + protected Integer retailTotalMore7D; + + @Column(name = "retail_sigma") + protected Integer retailTotalSigma; + + @Column(name = "retail_reliability") + protected Double retailReliability; + + + + @Column(name = "chain_total") + protected Integer chainTotal; + + @Column(name = "chain_total_1h") + protected Integer chainTotal1H; + + @Column(name = "chain_total_1d") + protected Integer chainTotal1D; + + @Column(name = "chain_total_today") + protected Integer chainTotalToday; + + @Column(name = "chain_total_7d") + protected Integer chainTotal7D; + + @Column(name = "chain_total_more_7d") + protected Integer chainTotalMore7D; + + @Column(name = "chain_sigma") + protected Integer chainTotalSigma; + + @Column(name = "chain_reliability") + protected Double chainReliability; + + @Column(name = "update_ts") + protected Date updateTs; + + @Column(name = "updated_by") + protected String updatedBy; + + @Override + public String getId() { + return id; + } + + @Override + public void setId(String id) { + this.id = id; + } + + @Override + public Date getUpdateTs() { + return updateTs; + } + + @Override + public void setUpdateTs(Date updateTs) { + this.updateTs = updateTs; + } + + @Override + public String getUpdatedBy() { + return updatedBy; + } + + @Override + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public Integer getRetailTotal() { + return retailTotal; + } + + public void setRetailTotal(Integer retailTotal) { + this.retailTotal = retailTotal; + } + + public Integer getRetailTotal1H() { + return retailTotal1H; + } + + public void setRetailTotal1H(Integer retailTotal1H) { + this.retailTotal1H = retailTotal1H; + } + + public Integer getRetailTotal1D() { + return retailTotal1D; + } + + public void setRetailTotal1D(Integer retailTotal1D) { + this.retailTotal1D = retailTotal1D; + } + + public Integer getRetailTotalToday() { + return retailTotalToday; + } + + public void setRetailTotalToday(Integer retailTotalToday) { + this.retailTotalToday = retailTotalToday; + } + + public Integer getRetailTotal7D() { + return retailTotal7D; + } + + public void setRetailTotal7D(Integer retailTotal7D) { + this.retailTotal7D = retailTotal7D; + } + + public Integer getRetailTotalMore7D() { + return retailTotalMore7D; + } + + public void setRetailTotalMore7D(Integer retailTotalMore7D) { + this.retailTotalMore7D = retailTotalMore7D; + } + + public Integer getRetailTotalSigma() { + return retailTotalSigma; + } + + public void setRetailTotalSigma(Integer retailTotalSigma) { + this.retailTotalSigma = retailTotalSigma; + } + + public Double getRetailReliability() { + return retailReliability; + } + + public void setRetailReliability(Double retailReliability) { + this.retailReliability = retailReliability; + } + + public Integer getChainTotal() { + return chainTotal; + } + + public void setChainTotal(Integer chainTotal) { + this.chainTotal = chainTotal; + } + + public Integer getChainTotal1H() { + return chainTotal1H; + } + + public void setChainTotal1H(Integer chainTotal1H) { + this.chainTotal1H = chainTotal1H; + } + + public Integer getChainTotal1D() { + return chainTotal1D; + } + + public void setChainTotal1D(Integer chainTotal1D) { + this.chainTotal1D = chainTotal1D; + } + + public Integer getChainTotalToday() { + return chainTotalToday; + } + + public void setChainTotalToday(Integer chainTotalToday) { + this.chainTotalToday = chainTotalToday; + } + + public Integer getChainTotal7D() { + return chainTotal7D; + } + + public void setChainTotal7D(Integer chainTotal7D) { + this.chainTotal7D = chainTotal7D; + } + + public Integer getChainTotalMore7D() { + return chainTotalMore7D; + } + + public void setChainTotalMore7D(Integer chainTotalMore7D) { + this.chainTotalMore7D = chainTotalMore7D; + } + + public Integer getChainTotalSigma() { + return chainTotalSigma; + } + + public void setChainTotalSigma(Integer chainTotalSigma) { + this.chainTotalSigma = chainTotalSigma; + } + + public Double getChainReliability() { + return chainReliability; + } + + public void setChainReliability(Double chainReliability) { + this.chainReliability = chainReliability; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/LicenseModel.java b/modules/global/src/com/cmobile/unifiedtms/entity/LicenseModel.java new file mode 100644 index 0000000..0d9c935 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/LicenseModel.java @@ -0,0 +1,213 @@ +package com.cmobile.unifiedtms.entity; + +import com.license4j.ValidationStatus; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +public class LicenseModel implements Serializable { + + private Long licenseID; + private String userFullname; + private String userRegisteredTo; + private String userCompany; + private String userCity; + private String userCountry; + private String userStreet; + private String userZipCode; + private String userEmail; + private String userFax; + private String userTelephone; + private Date licenseExpireDate; + private Date licenseGeneratedDateTime; + private String licenseProductName; + private String licenseSignature; + private String licenseValidProductEdition; + private String licenseValidProductID; + private String licenseValidProductVersion; + private String licenseHardwareID; + private Properties licenseProperties; + private Map licenseFeatures = new HashMap<>(); + private ValidationStatus validationStatus; + + public LicenseModel() {} + + public Long getLicenseID() { + return licenseID; + } + + public ValidationStatus getValidationStatus() { + return validationStatus; + } + + public void setValidationStatus(ValidationStatus validationStatus) { + this.validationStatus = validationStatus; + } + + public void setLicenseID(Long licenseID) { + this.licenseID = licenseID; + } + + public String getUserFullname() { + return userFullname; + } + + public void setUserFullname(String userFullname) { + this.userFullname = userFullname; + } + + public String getUserRegisteredTo() { + return userRegisteredTo; + } + + public void setUserRegisteredTo(String userRegisteredTo) { + this.userRegisteredTo = userRegisteredTo; + } + + public String getUserCompany() { + return userCompany; + } + + public void setUserCompany(String userCompany) { + this.userCompany = userCompany; + } + + public String getUserCity() { + return userCity; + } + + public void setUserCity(String userCity) { + this.userCity = userCity; + } + + public String getUserCountry() { + return userCountry; + } + + public void setUserCountry(String userCountry) { + this.userCountry = userCountry; + } + + public String getUserStreet() { + return userStreet; + } + + public void setUserStreet(String userStreet) { + this.userStreet = userStreet; + } + + public String getUserZipCode() { + return userZipCode; + } + + public void setUserZipCode(String userZipCode) { + this.userZipCode = userZipCode; + } + + public String getUserEmail() { + return userEmail; + } + + public void setUserEmail(String userEmail) { + this.userEmail = userEmail; + } + + public String getUserFax() { + return userFax; + } + + public void setUserFax(String userFax) { + this.userFax = userFax; + } + + public String getUserTelephone() { + return userTelephone; + } + + public void setUserTelephone(String userTelephone) { + this.userTelephone = userTelephone; + } + + public Date getLicenseExpireDate() { + return licenseExpireDate; + } + + public void setLicenseExpireDate(Date licenseExpireDate) { + this.licenseExpireDate = licenseExpireDate; + } + + public Date getLicenseGeneratedDateTime() { + return licenseGeneratedDateTime; + } + + public void setLicenseGeneratedDateTime(Date licenseGeneratedDateTime) { + this.licenseGeneratedDateTime = licenseGeneratedDateTime; + } + + public String getLicenseProductName() { + return licenseProductName; + } + + public void setLicenseProductName(String licenseProductName) { + this.licenseProductName = licenseProductName; + } + + public String getLicenseSignature() { + return licenseSignature; + } + + public void setLicenseSignature(String licenseSignature) { + this.licenseSignature = licenseSignature; + } + + public String getLicenseValidProductEdition() { + return licenseValidProductEdition; + } + + public void setLicenseValidProductEdition(String licenseValidProductEdition) { + this.licenseValidProductEdition = licenseValidProductEdition; + } + + public String getLicenseValidProductID() { + return licenseValidProductID; + } + + public void setLicenseValidProductID(String licenseValidProductID) { + this.licenseValidProductID = licenseValidProductID; + } + + public String getLicenseValidProductVersion() { + return licenseValidProductVersion; + } + + public void setLicenseValidProductVersion(String licenseValidProductVersion) { + this.licenseValidProductVersion = licenseValidProductVersion; + } + + public String getLicenseHardwareID() { + return licenseHardwareID; + } + + public void setLicenseHardwareID(String licenseHardwareID) { + this.licenseHardwareID = licenseHardwareID; + } + + public Properties getLicenseProperties() { + return licenseProperties; + } + + public void setLicenseProperties(Properties licenseProperties) { + this.licenseProperties = licenseProperties; + } + + public Map getLicenseFeatures() { + return licenseFeatures; + } + + public void setLicenseFeatures(Map licenseFeatures) { + this.licenseFeatures = licenseFeatures; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/Merchant.java b/modules/global/src/com/cmobile/unifiedtms/entity/Merchant.java new file mode 100644 index 0000000..83de8a1 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/Merchant.java @@ -0,0 +1,107 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.addon.sdbmt.entity.StandardTenantEntity; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.List; + +@NamePattern("%s|name") +@Table(name = "TMS_MERCHANT") +@Entity(name = "tms_Merchant") +public class Merchant extends StandardTenantEntity { + private static final long serialVersionUID = -2335692941575749058L; + + @NotNull + @Column(name = "NAME", nullable = false, length = 100) + protected String name; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TYPE_ID") + protected MerchantType type; + + @NotNull + @Column(name = "COMPANY_NAME", nullable = false, length = 100) + protected String companyName; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "DISTRICT_ID") + protected District district; + + @NotNull + @Column(name = "ADDRESS", nullable = false) + protected String address; + + @NotNull + @Column(name = "ZIPCODE", nullable = false, length = 5) + protected String zipcode; + + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.CASCADE) + @OneToMany(mappedBy = "merchant") + protected List contactPersons; + + public List getContactPersons() { + return contactPersons; + } + + public void setContactPersons(List contactPersons) { + this.contactPersons = contactPersons; + } + + public MerchantType getType() { + return type; + } + + public void setType(MerchantType type) { + this.type = type; + } + + public String getZipcode() { + return zipcode; + } + + public void setZipcode(String zipcode) { + this.zipcode = zipcode; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public District getDistrict() { + return district; + } + + public void setDistrict(District district) { + this.district = district; + } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/MerchantType.java b/modules/global/src/com/cmobile/unifiedtms/entity/MerchantType.java new file mode 100644 index 0000000..f25ea8f --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/MerchantType.java @@ -0,0 +1,39 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|name") +@Table(name = "TMS_MERCHANT_TYPE") +@Entity(name = "tms_MerchantType") +public class MerchantType extends StandardEntity { + private static final long serialVersionUID = -3884805971252828180L; + + @NotNull + @Column(name = "NAME", nullable = false, length = 100) + protected String name; + + @Column(name = "DESCRIPTION") + protected String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/ResponseCode.java b/modules/global/src/com/cmobile/unifiedtms/entity/ResponseCode.java new file mode 100644 index 0000000..193325e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/ResponseCode.java @@ -0,0 +1,53 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.entity.enums.TaskStatus; +import com.cmobile.unifiedtms.entity.enums.TrxType; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|code") +@Table(name = "TMS_RESPONSE_CODE") +@Entity(name = "tms_ResponseCode") +public class ResponseCode extends StandardEntity { + private static final long serialVersionUID = 2184358567137236838L; + + @Column(name = "TYPE", nullable = false, unique = false, length = 10) + protected String type; + + @NotNull + @Column(name = "CODE", nullable = false, unique = false, length = 2) + protected String code; + + @NotNull + @Column(name = "DESCRIPTION", nullable = false, length = 255) + protected String desc; + + public TrxType getType() { + return type == null ? null : TrxType.fromId(type); + } + + public void setType(TrxType type) { + this.type = type == null ? null : type.getId(); + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/States.java b/modules/global/src/com/cmobile/unifiedtms/entity/States.java new file mode 100644 index 0000000..321852d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/States.java @@ -0,0 +1,44 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; + +@NamePattern("%s|name") +@Table(name = "TMS_STATES") +@Entity(name = "tms_States") +public class States extends StandardEntity { + private static final long serialVersionUID = 2291545791294287824L; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "COUNTRY_ID") + protected Country country; + + @NotNull + @Column(name = "NAME", nullable = false, length = 50) + protected String name; + + public Country getCountry() { + return country; + } + + public void setCountry(Country country) { + this.country = country; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/Terminal.java b/modules/global/src/com/cmobile/unifiedtms/entity/Terminal.java new file mode 100644 index 0000000..abb4827 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/Terminal.java @@ -0,0 +1,343 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.entity.enums.TerminalHeartBeatStatus; +import com.haulmont.addon.sdbmt.entity.StandardTenantEntity; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +@NamePattern("%s|sn") +@Table(name = "TMS_TERMINAL", indexes = { + @Index(name = "IDX_TMS_TERMINAL_UNQ", columnList = "SN, IMEI", unique = true) +}) +@Entity(name = "tms_Terminal") +public class Terminal extends StandardTenantEntity { + private static final long serialVersionUID = -7294193473253942325L; + + @NotNull + @Column(name = "SN", nullable = false, unique = true, length = 30) + protected String sn; + + @NotNull + @Column(name = "IMEI", nullable = false, unique = true, length = 25) + protected String imei; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "MODEL_ID") + protected DeviceModel model; + + @JoinTable(name = "TMS_TERMINAL_GROUP_LINK", joinColumns = @JoinColumn(name = "TERMINAL_ID"), inverseJoinColumns = @JoinColumn(name = "TERMINAL_GROUP_ID")) + @ManyToMany + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.UNLINK) + protected List group; + + @NotNull + @OnDeleteInverse(DeletePolicy.DENY) + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "MERCHANT_ID") + protected Merchant merchant; + + @OnDeleteInverse(DeletePolicy.DENY) + @OnDelete(DeletePolicy.UNLINK) + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "PROFILE_ID") + protected DeviceProfile profile; + + @JoinTable(name = "TMS_DOWNLOAD_TASK_TERMINAL_LINK", + joinColumns = @JoinColumn(name = "TERMINAL_ID"), + inverseJoinColumns = @JoinColumn(name = "DOWNLOAD_TASK_ID")) + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + protected List downloadTasks; + + @OneToOne(fetch = FetchType.LAZY, mappedBy = "terminal") + protected TerminalLink terminalLink; + + @Column(name = "IMPORT_DEFAULT") + protected Boolean importDefault; + + @Column(name = "HEARTBEAT_STATUS") + protected Integer heartBeatStatus; + + @Column(name = "LAST_HEARTBEAT_TIME") + protected Date lastHeartBeatTime; + + @Column(name = "LAST_HEARTBEAT_ID") + protected UUID lastHeartBeatId; + + @Column(name = "LAST_INIT_TIME") + protected Date lastInitTime; + + @Column(name = "LAST_INIT_AID_TIME") + protected Date lastInitAidTime; + + @Column(name = "LAST_INIT_CAPK_TIME") + protected Date lastInitCapkTime; + + @Column(name = "LAST_INIT_CONTACTLESS_AID_TIME") + protected Date lastInitContactlessAidTime; + + @Column(name = "LAST_INIT_CARDS_TIME") + protected Date lastInitCardsTime; + + @Column(name = "LAST_INIT_TERMINAL_TIME") + protected Date lastInitTerminalTime; + + @Column(name = "LATITUDE") + protected Double latitude; + + @Column(name = "LONGITUDE") + protected Double longitude; + + @Column(name = "LAST_DIAGNOSTIC_TIME") + protected Date lastDiagnosticTime; + + @Column(name = "LAST_DIAGNOSTIC_ID") + protected UUID lastDiagnosticId; + + @Column(name = "APP_VERSION", nullable = true, length = 50) + protected String appVersion; + + @Column(name = "LAUNCHER_VERSION", nullable = true, length = 50) + protected String launcherVersion; + + @Column(name = "VFS_VERSION", nullable = true, length = 50) + protected String vfsVersion; + + @Column(name = "VFSS_VERSION", nullable = true, length = 50) + protected String vfssVersion; + + @Column(name = "CELL_NAME") + protected String cellName; + + public Boolean getImportDefault() { + return importDefault; + } + + public void setImportDefault(Boolean importDefault) { + this.importDefault = importDefault; + } + + public TerminalLink getTerminalLink() { + return terminalLink; + } + + public void setTerminalLink(TerminalLink terminalLink) { + this.terminalLink = terminalLink; + } + + public List getDownloadTasks() { + return downloadTasks; + } + + public void setDownloadTasks(List downloadTasks) { + this.downloadTasks = downloadTasks; + } + + public DeviceProfile getProfile() { + return profile; + } + + public void setProfile(DeviceProfile profile) { + this.profile = profile; + } + + public void setGroup(List group) { + this.group = group; + } + + public List getGroup() { + return group; + } + + public DeviceModel getModel() { + return model; + } + + public void setModel(DeviceModel model) { + this.model = model; + } + + public Merchant getMerchant() { + return merchant; + } + + public void setMerchant(Merchant merchant) { + this.merchant = merchant; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public TerminalHeartBeatStatus getHeartBeatStatus() { + return heartBeatStatus != null ? null : TerminalHeartBeatStatus.fromId(heartBeatStatus); + } + + public void setHeartBeatStatus(TerminalHeartBeatStatus heartBeatStatus) { + this.heartBeatStatus = heartBeatStatus == null ? null : heartBeatStatus.getId(); + } + + public Date getLastHeartBeatTime() { + return lastHeartBeatTime; + } + + public void setLastHeartBeatTime(Date lastHeartBeatTime) { + this.lastHeartBeatTime = lastHeartBeatTime; + } + + public UUID getLastHeartBeatId() { + return lastHeartBeatId; + } + + public void setLastHeartBeatId(UUID lastHeartBeatId) { + this.lastHeartBeatId = lastHeartBeatId; + } + + public Date getLastInitTime() { + return lastInitTime; + } + + public void setLastInitTime(Date lastInitTime) { + this.lastInitTime = lastInitTime; + } + + public Date getLastInitAidTime() { + return lastInitAidTime; + } + + public void setLastInitAidTime(Date lastInitAidTime) { + this.lastInitAidTime = lastInitAidTime; + } + + public Date getLastInitCapkTime() { + return lastInitCapkTime; + } + + public void setLastInitCapkTime(Date lastInitCapkTime) { + this.lastInitCapkTime = lastInitCapkTime; + } + + public Date getLastInitContactlessAidTime() { + return lastInitContactlessAidTime; + } + + public void setLastInitContactlessAidTime(Date lastInitContactlessAidTime) { + this.lastInitContactlessAidTime = lastInitContactlessAidTime; + } + + public Date getLastInitCardsTime() { + return lastInitCardsTime; + } + + public void setLastInitCardsTime(Date lastInitCardsTime) { + this.lastInitCardsTime = lastInitCardsTime; + } + + public Date getLastInitTerminalTime() { + return lastInitTerminalTime; + } + + public void setLastInitTerminalTime(Date lastInitTerminalTime) { + this.lastInitTerminalTime = lastInitTerminalTime; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Date getLastDiagnosticTime() { + return lastDiagnosticTime; + } + + public void setLastDiagnosticTime(Date lastDiagnosticTime) { + this.lastDiagnosticTime = lastDiagnosticTime; + } + + public UUID getLastDiagnosticId() { + return lastDiagnosticId; + } + + public void setLastDiagnosticId(UUID lastDiagnosticId) { + this.lastDiagnosticId = lastDiagnosticId; + } + + public String getAppVersion() { + return appVersion; + } + + public void setAppVersion(String appVersion) { + this.appVersion = appVersion; + } + + public String getLauncherVersion() { + return launcherVersion; + } + + public void setLauncherVersion(String launcherVersion) { + this.launcherVersion = launcherVersion; + } + + public String getVfsVersion() { + return vfsVersion; + } + + public void setVfsVersion(String vfsVersion) { + this.vfsVersion = vfsVersion; + } + + public String getVfssVersion() { + return vfssVersion; + } + + public void setVfssVersion(String vfssVersion) { + this.vfssVersion = vfssVersion; + } + + public void setHeartBeatStatus(Integer heartBeatStatus) { + this.heartBeatStatus = heartBeatStatus; + } + + public String getCellName() { + return cellName; + } + + public void setCellName(String cellName) { + this.cellName = cellName; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalAckUpdate.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalAckUpdate.java new file mode 100644 index 0000000..e8481e5 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalAckUpdate.java @@ -0,0 +1,108 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; + +import javax.persistence.*; +import java.util.Date; + +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@NamePattern("%s|sn") +@Table(name = "TMS_TERMINAL_ACK_UPDATE") +@Entity(name = "tms_TerminalAckUpdate") +public class TerminalAckUpdate extends BaseUuidEntity implements Creatable { + private static final long serialVersionUID = 6491584963030369358L; + + @Column(name = "SN") + protected String sn; + + @Column(name = "LAST_INIT_TIME") + protected Date lastInitTime; + + @Column(name = "SYNC_START_TIME") + protected Date syncStartTime; + + @Column(name = "SYNC_END_TIME") + protected Date syncEndTime; + + @Column(name = "RETRY_COUNT") + protected Integer retryCount; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @Column(name = "STATUS") + protected String status; + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Date getLastInitTime() { + return lastInitTime; + } + + public void setLastInitTime(Date lastInitTime) { + this.lastInitTime = lastInitTime; + } + + public Date getSyncStartTime() { + return syncStartTime; + } + + public void setSyncStartTime(Date syncStartTime) { + this.syncStartTime = syncStartTime; + } + + public Date getSyncEndTime() { + return syncEndTime; + } + + public void setSyncEndTime(Date syncEndTime) { + this.syncEndTime = syncEndTime; + } + + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroup.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroup.java new file mode 100644 index 0000000..b85ba75 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroup.java @@ -0,0 +1,56 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.StandardEntity; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.List; + +@NamePattern("%s|name") +@Table(name = "TMS_TERMINAL_GROUP") +@Entity(name = "tms_TerminalGroup") +public class TerminalGroup extends StandardEntity { + private static final long serialVersionUID = 8125274631131458996L; + + @NotNull + @Column(name = "NAME", nullable = false, length = 100) + protected String name; + + @Column(name = "DESCRIPTION") + protected String description; + @JoinTable(name = "TMS_TERMINAL_GROUP_LINK", + joinColumns = @JoinColumn(name = "TERMINAL_GROUP_ID"), + inverseJoinColumns = @JoinColumn(name = "TERMINAL_ID")) + @OnDeleteInverse(DeletePolicy.UNLINK) + @OnDelete(DeletePolicy.UNLINK) + @ManyToMany + protected List terminals; + + public List getTerminals() { + return terminals; + } + + public void setTerminals(List terminals) { + this.terminals = terminals; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroupImport.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroupImport.java new file mode 100644 index 0000000..3344894 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalGroupImport.java @@ -0,0 +1,67 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.MetaClass; +import com.haulmont.chile.core.annotations.MetaProperty; +import com.haulmont.cuba.core.entity.BaseStringIdEntity; + +import javax.persistence.Id; + +@MetaClass(name = "tms_TerminalGroupImport") +public class TerminalGroupImport extends BaseStringIdEntity { + private static final long serialVersionUID = -1489621948034643389L; + + @Id + @MetaProperty(mandatory = true) + protected String sn; + + @MetaProperty + protected String tid; + + @MetaProperty + protected Boolean snFound; + + @MetaProperty + protected Boolean tidFound; + + public Boolean getTidFound() { + return tidFound; + } + + public void setTidFound(Boolean tidFound) { + this.tidFound = tidFound; + } + + public Boolean getSnFound() { + return snFound; + } + + public void setSnFound(Boolean snFound) { + this.snFound = snFound; + } + + public String getTid() { + return tid; + } + + public void setTid(String tid) { + this.tid = tid; + } + + @Override + public void setId(String id) { + this.sn = id; + } + + @Override + public String getId() { + return sn; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalHeartBeat.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalHeartBeat.java new file mode 100644 index 0000000..52e1fdd --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalHeartBeat.java @@ -0,0 +1,164 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.global.DesignSupport; + +import javax.persistence.*; +import java.util.Date; +import java.util.UUID; + +@DesignSupport("{'dbView':true,'imported':true,'generateDdl':false}") +@Table(name = "tms_v_terminal_heart_beat") +@Entity(name = "tms_TerminalHeartBeat") +public class TerminalHeartBeat extends BaseUuidEntity implements Versioned, Creatable { + private static final long serialVersionUID = -3539537453020368691L; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "create_ts") + protected Date createTs; + + @Column(name = "created_by", length = 50) + protected String createdBy; + + @Version + @Column(name = "version") + protected Integer version; + + @Column(name = "battery_percentage") + protected Integer batteryPercentage; + + @Column(name = "battery_temp") + protected Double batteryTemp; + + @Column(name = "latitude") + protected Double latitude; + + @Column(name = "longitude") + protected Double longitude; + + @Column(name = "terminal_sn", length = 30) + protected String terminalSn; + + @Column(name = "cell_name") + protected String cellName; + + @Column(name = "cell_type") + protected String cellType; + + @Column(name = "cell_strength") + protected Integer cellStrength; + + @Column(name = "wifi_name") + protected String wifiName; + + @Column(name = "wifi_strength") + protected Integer wifiStrength; + + public String getTerminalSn() { + return terminalSn; + } + + public void setTerminalSn(String terminalSn) { + this.terminalSn = terminalSn; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getCreateTs() { + return createTs; + } + + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public String getCellName() { + return cellName; + } + + public void setCellName(String cellName) { + this.cellName = cellName; + } + + public String getCellType() { + return cellType; + } + + public void setCellType(String cellType) { + this.cellType = cellType; + } + + public Integer getCellStrength() { + return cellStrength; + } + + public void setCellStrength(Integer cellStrength) { + this.cellStrength = cellStrength; + } + + public String getWifiName() { + return wifiName; + } + + public void setWifiName(String wifiName) { + this.wifiName = wifiName; + } + + public Integer getWifiStrength() { + return wifiStrength; + } + + public void setWifiStrength(Integer wifiStrength) { + this.wifiStrength = wifiStrength; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalImportBean.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalImportBean.java new file mode 100644 index 0000000..d67e402 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalImportBean.java @@ -0,0 +1,209 @@ +package com.cmobile.unifiedtms.entity; + +import java.io.Serializable; + +/** + * + * @author Jaka + */ +public class TerminalImportBean implements Serializable { + + private String sn; + private String imei; + private String modelName; + private String merchantName; + private String profileName; + private String _groupNames; + private String templateTerminalId; + private String terminalId; + private String merchantId; + private String merchantName1; + private String merchantName2; + private String merchantName3; + private String merchantName4; + private String merchantName5; + + /** + * @return the sn + */ + public String getSn() { + return sn; + } + + /** + * @param sn the sn to set + */ + public void setSn(String sn) { + this.sn = sn; + } + + /** + * @return the imei + */ + public String getImei() { + return imei; + } + + /** + * @param imei the imei to set + */ + public void setImei(String imei) { + this.imei = imei; + } + + /** + * @return the modelName + */ + public String getModelName() { + return modelName; + } + + /** + * @param modelName the modelName to set + */ + public void setModelName(String modelName) { + this.modelName = modelName; + } + + /** + * @return the merchantName + */ + public String getMerchantName() { + return merchantName; + } + + /** + * @param merchantName the merchantName to set + */ + public void setMerchantName(String merchantName) { + this.merchantName = merchantName; + } + + /** + * @return the profileName + */ + public String getProfileName() { + return profileName; + } + + /** + * @param profileName the profileName to set + */ + public void setProfileName(String profileName) { + this.profileName = profileName; + } + + /** + * @return the _groupNames + */ + public String getGroupNames() { + return _groupNames; + } + + /** + * @param _groupNames the _groupNames to set + */ + public void setGroupNames(String _groupNames) { + this._groupNames = _groupNames; + } + + /** + * @return the templateTerminalId + */ + public String getTemplateTerminalId() { + return templateTerminalId; + } + + /** + * @param templateTerminalId the templateTerminalId to set + */ + public void setTemplateTerminalId(String templateTerminalId) { + this.templateTerminalId = templateTerminalId; + } + + /** + * @return the terminalId + */ + public String getTerminalId() { + return terminalId; + } + + /** + * @param terminalId the terminalId to set + */ + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + /** + * @return the merchantId + */ + public String getMerchantId() { + return merchantId; + } + + /** + * @param merchantId the merchantId to set + */ + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + /** + * @return the merchantName1 + */ + public String getMerchantName1() { + return merchantName1; + } + + /** + * @param merchantName1 the merchantName1 to set + */ + public void setMerchantName1(String merchantName1) { + this.merchantName1 = merchantName1; + } + + /** + * @return the merchantName2 + */ + public String getMerchantName2() { + return merchantName2; + } + + /** + * @param merchantName2 the merchantName2 to set + */ + public void setMerchantName2(String merchantName2) { + this.merchantName2 = merchantName2; + } + + /** + * @return the merchantName3 + */ + public String getMerchantName3() { + return merchantName3; + } + + /** + * @param merchantName3 the merchantName3 to set + */ + public void setMerchantName3(String merchantName3) { + this.merchantName3 = merchantName3; + } + + public String getMerchantName4() { + return merchantName4; + } + + public void setMerchantName4(String merchantName4) { + this.merchantName4 = merchantName4; + } + + public String getMerchantName5() { + return merchantName5; + } + + public void setMerchantName5(String merchantName5) { + this.merchantName5 = merchantName5; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastDiagnosticInfo.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastDiagnosticInfo.java new file mode 100644 index 0000000..f386d75 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastDiagnosticInfo.java @@ -0,0 +1,305 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.global.DesignSupport; + +import javax.persistence.*; +import java.util.Date; +import java.util.UUID; + +@DesignSupport("{'dbView':true,'imported':true,'generateDdl':false}") +@NamePattern("%s|terminalSn") +@Table(name = "tms_v_terminal_last_diagnostic_info") +@Entity(name = "tms_TerminalLastDiagnosticInfo") +public class TerminalLastDiagnosticInfo extends BaseUuidEntity implements Creatable { + private static final long serialVersionUID = 3273694768616434323L; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "create_ts") + protected Date createTs; + + @Column(name = "created_by", length = 50) + protected String createdBy; + + @Column(name = "available_flash_memory") + protected Long availableFlashMemory; + + @Column(name = "available_memory") + protected Long availableMemory; + + @Column(name = "battery_percentage") + protected Integer batteryPercentage; + + @Column(name = "battery_temp") + protected Double batteryTemp; + + @Column(name = "charge_times") + protected Integer chargeTimes; + + @Column(name = "current_boot_time") + protected Integer currentBootTime; + + @Column(name = "dip_inserting_times") + protected Integer dipInsertingTimes; + + @Column(name = "front_camera_open_times") + protected Integer frontCameraOpenTimes; + + @Column(name = "installed_apps", length = 1000) + protected String installedApps; + + @Column(name = "latitude") + protected Double latitude; + + @Column(name = "longitude") + protected Double longitude; + + @Column(name = "meid", length = 20) + protected String meid; + + @Column(name = "nfc_card_reading_times") + protected Integer nfcCardReadingTimes; + + @Column(name = "rear_camera_open_times") + protected Integer rearCameraOpenTimes; + + @Column(name = "swiping_card_times") + protected Integer swipingCardTimes; + + @Column(name = "switching_times") + protected Integer switchingTimes; + + @Column(name = "terminal_id") + protected UUID terminal; + + @Column(name = "terminal_sn", length = 30) + protected String terminalSn; + + @Column(name = "total_boot_time") + protected Integer totalBootTime; + + @Column(name = "total_flash_memory") + protected Long totalFlashMemory; + + @Column(name = "total_length_printed") + protected Double totalLengthPrinted; + + @Column(name = "total_memory") + protected Long totalMemory; + + @Column(name = "total_mobile_data") + protected Long totalMobileData; + + @Column(name = "TERMINAL_EXT_ID") + protected String terminalExtId; + + public String getTerminalExtId() { + return terminalExtId; + } + + public void setTerminalExtId(String terminalExtId) { + this.terminalExtId = terminalExtId; + } + + public void setTotalLengthPrinted(Double totalLengthPrinted) { + this.totalLengthPrinted = totalLengthPrinted; + } + + public Double getTotalLengthPrinted() { + return totalLengthPrinted; + } + + public void setAvailableFlashMemory(Long availableFlashMemory) { + this.availableFlashMemory = availableFlashMemory; + } + + public Long getAvailableFlashMemory() { + return availableFlashMemory; + } + + public void setAvailableMemory(Long availableMemory) { + this.availableMemory = availableMemory; + } + + public Long getAvailableMemory() { + return availableMemory; + } + + public void setTotalFlashMemory(Long totalFlashMemory) { + this.totalFlashMemory = totalFlashMemory; + } + + public Long getTotalFlashMemory() { + return totalFlashMemory; + } + + public void setTotalMemory(Long totalMemory) { + this.totalMemory = totalMemory; + } + + public Long getTotalMemory() { + return totalMemory; + } + + public void setTotalMobileData(Long totalMobileData) { + this.totalMobileData = totalMobileData; + } + + public Long getTotalMobileData() { + return totalMobileData; + } + + public Integer getTotalBootTime() { + return totalBootTime; + } + + public void setTotalBootTime(Integer totalBootTime) { + this.totalBootTime = totalBootTime; + } + + public String getTerminalSn() { + return terminalSn; + } + + public void setTerminalSn(String terminalSn) { + this.terminalSn = terminalSn; + } + + public UUID getTerminal() { + return terminal; + } + + public void setTerminal(UUID terminal) { + this.terminal = terminal; + } + + public Integer getSwitchingTimes() { + return switchingTimes; + } + + public void setSwitchingTimes(Integer switchingTimes) { + this.switchingTimes = switchingTimes; + } + + public Integer getSwipingCardTimes() { + return swipingCardTimes; + } + + public void setSwipingCardTimes(Integer swipingCardTimes) { + this.swipingCardTimes = swipingCardTimes; + } + + public Integer getRearCameraOpenTimes() { + return rearCameraOpenTimes; + } + + public void setRearCameraOpenTimes(Integer rearCameraOpenTimes) { + this.rearCameraOpenTimes = rearCameraOpenTimes; + } + + public Integer getNfcCardReadingTimes() { + return nfcCardReadingTimes; + } + + public void setNfcCardReadingTimes(Integer nfcCardReadingTimes) { + this.nfcCardReadingTimes = nfcCardReadingTimes; + } + + public String getMeid() { + return meid; + } + + public void setMeid(String meid) { + this.meid = meid; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public String getInstalledApps() { + return installedApps; + } + + public void setInstalledApps(String installedApps) { + this.installedApps = installedApps; + } + + public Integer getFrontCameraOpenTimes() { + return frontCameraOpenTimes; + } + + public void setFrontCameraOpenTimes(Integer frontCameraOpenTimes) { + this.frontCameraOpenTimes = frontCameraOpenTimes; + } + + public Integer getDipInsertingTimes() { + return dipInsertingTimes; + } + + public void setDipInsertingTimes(Integer dipInsertingTimes) { + this.dipInsertingTimes = dipInsertingTimes; + } + + public Integer getCurrentBootTime() { + return currentBootTime; + } + + public void setCurrentBootTime(Integer currentBootTime) { + this.currentBootTime = currentBootTime; + } + + public Integer getChargeTimes() { + return chargeTimes; + } + + public void setChargeTimes(Integer chargeTimes) { + this.chargeTimes = chargeTimes; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getCreateTs() { + return createTs; + } + + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastHeartBeat.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastHeartBeat.java new file mode 100644 index 0000000..b2a7291 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastHeartBeat.java @@ -0,0 +1,197 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.global.DesignSupport; + +import javax.persistence.*; +import java.util.Date; +import java.util.UUID; + +@DesignSupport("{'dbView':true,'imported':true,'generateDdl':false}") +@Table(name = "tms_v_terminal_last_heart_beat") +@Entity(name = "tms_TerminalLastHeartBeat") +public class TerminalLastHeartBeat extends BaseUuidEntity implements Versioned, Creatable { + private static final long serialVersionUID = -3539537453020368691L; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "create_ts") + protected Date createTs; + + @Column(name = "created_by", length = 50) + protected String createdBy; + + @Version + @Column(name = "version") + protected Integer version; + + @Column(name = "battery_percentage") + protected Integer batteryPercentage; + + @Column(name = "battery_temp") + protected Double batteryTemp; + + @Column(name = "latitude") + protected Double latitude; + + @Column(name = "longitude") + protected Double longitude; + + @Column(name = "terminal_id") + protected UUID terminalId; + + @Column(name = "TERMINAL_EXT_ID") + protected String terminalExtId; + + @Column(name = "terminal_sn", length = 30) + protected String terminalSn; + + @Column(name = "state") + protected String state; + + @Column(name = "cell_name") + protected String cellName; + + @Column(name = "cell_type") + protected String cellType; + + @Column(name = "cell_strength") + protected Integer cellStrength; + + @Column(name = "wifi_name") + protected String wifiName; + + @Column(name = "wifi_strength") + protected Integer wifiStrength; + + public String getTerminalExtId() { + return terminalExtId; + } + + public void setTerminalExtId(String terminalExtId) { + this.terminalExtId = terminalExtId; + } + + public void setTerminalId(UUID terminalId) { + this.terminalId = terminalId; + } + + public UUID getTerminalId() { + return terminalId; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getTerminalSn() { + return terminalSn; + } + + public void setTerminalSn(String terminalSn) { + this.terminalSn = terminalSn; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + public String getCreatedBy() { + return createdBy; + } + + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public Date getCreateTs() { + return createTs; + } + + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public String getCellName() { + return cellName; + } + + public void setCellName(String cellName) { + this.cellName = cellName; + } + + public String getCellType() { + return cellType; + } + + public void setCellType(String cellType) { + this.cellType = cellType; + } + + public Integer getCellStrength() { + return cellStrength; + } + + public void setCellStrength(Integer cellStrength) { + this.cellStrength = cellStrength; + } + + public String getWifiName() { + return wifiName; + } + + public void setWifiName(String wifiName) { + this.wifiName = wifiName; + } + + public Integer getWifiStrength() { + return wifiStrength; + } + + public void setWifiStrength(Integer wifiStrength) { + this.wifiStrength = wifiStrength; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastStepUpdate.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastStepUpdate.java new file mode 100644 index 0000000..c18647c --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastStepUpdate.java @@ -0,0 +1,75 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; + +import javax.persistence.*; +import java.util.Date; + +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@NamePattern("%s|sn") +@Table(name = "TMS_TERMINAL_LAST_STEP_UPDATE") +@Entity(name = "tms_TerminalLastStepUpdate") +public class TerminalLastStepUpdate extends BaseUuidEntity implements Creatable { + private static final long serialVersionUID = 6491584963030369358L; + + @Column(name = "SN") + protected String sn; + + @Column(name = "STEP_NAME") + protected String stepName; + + @Column(name = "LAST_INIT_TIME") + protected Date lastInitTime; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public Date getLastInitTime() { + return lastInitTime; + } + + public void setLastInitTime(Date lastInitTime) { + this.lastInitTime = lastInitTime; + } + + public String getStepName() { + return stepName; + } + + public void setStepName(String stepName) { + this.stepName = stepName; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastUpdate.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastUpdate.java new file mode 100644 index 0000000..46bb4ac --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLastUpdate.java @@ -0,0 +1,89 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +@NamePattern("%s|sn") +@Table(name = "TMS_TERMINAL_LAST_UPDATE") +@Entity(name = "tms_TerminalLastUpdate") +public class TerminalLastUpdate extends BaseUuidEntity implements Creatable { + private static final long serialVersionUID = 6491584963030369358L; + + @Column(name = "SN") + protected String sn; + + @Column(name = "HAS_UPDATE") + protected Boolean hasUpdate; + + @Column(name = "FORCE_UPDATE") + protected Boolean forceUpdate; + + @Column(name = "LAST_INIT_TIME") + protected Date lastInitTime; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + public Date getLastInitTime() { + return lastInitTime; + } + + public void setLastInitTime(Date lastInitTime) { + this.lastInitTime = lastInitTime; + } + + public Boolean getHasUpdate() { + return hasUpdate; + } + + public void setHasUpdate(Boolean hasUpdate) { + this.hasUpdate = hasUpdate; + } + + public Boolean getForceUpdate() { + return forceUpdate; + } + + public void setForceUpdate(Boolean forceUpdate) { + this.forceUpdate = forceUpdate; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLink.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLink.java new file mode 100644 index 0000000..b2f3333 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalLink.java @@ -0,0 +1,109 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.ext.entity.TerminalExt; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.*; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@NamePattern("%s|terminal") +@Table(name = "TMS_TERMINAL_LINK") +@Entity(name = "tms_TerminalLink") +public class TerminalLink extends BaseUuidEntity implements Creatable, Updatable, Versioned { + private static final long serialVersionUID = -2787884093282328769L; + + @NotNull + @OneToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TERMINAL_ID") + protected Terminal terminal; + + @NotNull + @OneToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "TERMINAL_EXT_ID") + protected TerminalExt terminalExt; + + @Version + @Column(name = "VERSION", nullable = false) + protected Integer version; + + @Column(name = "CREATE_TS") + protected Date createTs; + + @Column(name = "CREATED_BY", length = 50) + protected String createdBy; + + @Column(name = "UPDATE_TS") + protected Date updateTs; + + @Column(name = "UPDATED_BY", length = 50) + protected String updatedBy; + + public TerminalExt getTerminalExt() { + return terminalExt; + } + + public void setTerminalExt(TerminalExt terminalExt) { + this.terminalExt = terminalExt; + } + + public Terminal getTerminal() { + return terminal; + } + + public void setTerminal(Terminal terminal) { + this.terminal = terminal; + } + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + @Override + public Date getUpdateTs() { + return updateTs; + } + + @Override + public void setUpdateTs(Date updateTs) { + this.updateTs = updateTs; + } + + @Override + public String getUpdatedBy() { + return updatedBy; + } + + @Override + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfiling.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfiling.java new file mode 100644 index 0000000..524f4fb --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfiling.java @@ -0,0 +1,96 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.*; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.persistence.Entity; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@NamePattern("%s|file") +@Table(name = "TMS_TERMINAL_PROFILING") +@Entity(name = "tms_TerminalProfiling") +public class TerminalProfiling extends BaseUuidEntity implements Versioned, Creatable { + private static final long serialVersionUID = 2184358567137236838L; + + @OnDeleteInverse(DeletePolicy.DENY) + @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + @JoinColumn(name = "FILE") + protected FileDescriptor file; + + @Version + @Column( + name = "VERSION", + nullable = false + ) + protected Integer version; + @Column( + name = "CREATE_TS" + ) + protected Date createTs; + @Column( + name = "CREATED_BY", + length = 50 + ) + protected String createdBy; + + @OnDeleteInverse(DeletePolicy.DENY) + @OnDelete(DeletePolicy.CASCADE) + @OneToMany(mappedBy = "profiling", cascade = CascadeType.PERSIST, orphanRemoval = true) + protected List items; + + public FileDescriptor getFile() { + return file; + } + + public void setFile(FileDescriptor file) { + this.file = file; + } + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date date) { + this.createTs = date; + } + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer integer) { + this.version = version; + } + + public List getItems() { + if(items == null) { + items = new ArrayList<>(); + } + return items; + } + + public void setItems(List items) { + this.items = items; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfilingItem.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfilingItem.java new file mode 100644 index 0000000..ec5d1cc --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalProfilingItem.java @@ -0,0 +1,236 @@ +package com.cmobile.unifiedtms.entity; + +import com.cmobile.unifiedtms.ext.entity.Acquirer; +import com.haulmont.chile.core.annotations.NamePattern; +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.FileDescriptor; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.entity.annotation.Lookup; +import com.haulmont.cuba.core.entity.annotation.LookupType; +import com.haulmont.cuba.core.entity.annotation.OnDelete; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.*; +import javax.validation.constraints.NotNull; +import java.util.Date; + +@NamePattern("%s|sn") +@Table(name = "TMS_TERMINAL_PROFILING_ITEMS") +@Entity(name = "tms_TerminalProfilingItems") +public class TerminalProfilingItem extends BaseUuidEntity implements Creatable { + private static final long serialVersionUID = 2184358567137236838L; + + @OnDeleteInverse(DeletePolicy.CASCADE) + @OnDelete(DeletePolicy.DENY) + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "PROFILING_ID") + protected TerminalProfiling profiling; + + @NotNull + @Column(name = "sn", nullable = false, length = 30) + protected String sn; + + @NotNull + @Column(name = "imei", nullable = false, length = 25) + protected String imei; + + @NotNull + @Column(name = "model_name", nullable = false, length = 50) + protected String modelName; + + @NotNull + @Column(name = "merchant_name", nullable = false, length = 100) + protected String merchantName; + + @NotNull + @Column(name = "profile_name", nullable = false, length = 50) + protected String profileName; + + @NotNull + @Column(name = "group_names", nullable = false, length = 255) + protected String groupNames; + + @NotNull + @Column(name = "terminal_id_template", nullable = false, length = 8) + protected String terminalIdTemplate; + + @NotNull + @Column(name = "terminal_id", nullable = false, length = 8) + protected String terminalId; + + @NotNull + @Column(name = "merchant_id", nullable = false, length = 15) + protected String merchantId; + + @NotNull + @Column(name = "merchant_name1", nullable = false, length = 30) + protected String merchantName1; + + @NotNull + @Column(name = "merchant_name2", nullable = true, length = 30) + protected String merchantName2; + + @NotNull + @Column(name = "merchant_name3", nullable = true, length = 30) + protected String merchantName3; + + @NotNull + @Column(name = "merchant_name4", nullable = true, length = 30) + protected String merchantName4; + + @NotNull + @Column(name = "merchant_name5", nullable = true, length = 30) + protected String merchantName5; + + @Column( + name = "CREATE_TS" + ) + protected Date createTs; + @Column( + name = "CREATED_BY", + length = 50 + ) + protected String createdBy; + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date date) { + this.createTs = date; + } + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public TerminalProfiling getProfiling() { + return profiling; + } + + public void setProfiling(TerminalProfiling profiling) { + this.profiling = profiling; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public String getModelName() { + return modelName; + } + + public void setModelName(String modelName) { + this.modelName = modelName; + } + + public String getMerchantName() { + return merchantName; + } + + public void setMerchantName(String merchantName) { + this.merchantName = merchantName; + } + + public String getProfileName() { + return profileName; + } + + public void setProfileName(String profileName) { + this.profileName = profileName; + } + + public String getGroupNames() { + return groupNames; + } + + public void setGroupNames(String groupNames) { + this.groupNames = groupNames; + } + + public String getTerminalIdTemplate() { + return terminalIdTemplate; + } + + public void setTerminalIdTemplate(String terminalIdTemplate) { + this.terminalIdTemplate = terminalIdTemplate; + } + + public String getTerminalId() { + return terminalId; + } + + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + public String getMerchantId() { + return merchantId; + } + + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + public String getMerchantName1() { + return merchantName1; + } + + public void setMerchantName1(String merchantName1) { + this.merchantName1 = merchantName1; + } + + public String getMerchantName2() { + return merchantName2; + } + + public void setMerchantName2(String merchantName2) { + this.merchantName2 = merchantName2; + } + + public String getMerchantName3() { + return merchantName3; + } + + public void setMerchantName3(String merchantName3) { + this.merchantName3 = merchantName3; + } + + public String getMerchantName4() { + return merchantName4; + } + + public void setMerchantName4(String merchantName4) { + this.merchantName4 = merchantName4; + } + + public String getMerchantName5() { + return merchantName5; + } + + public void setMerchantName5(String merchantName5) { + this.merchantName5 = merchantName5; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/TerminalReport.java b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalReport.java new file mode 100644 index 0000000..263a16e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/TerminalReport.java @@ -0,0 +1,477 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.cuba.core.entity.BaseStringIdEntity; +import com.haulmont.cuba.core.global.DesignSupport; + +import javax.persistence.*; +import java.util.Date; + +@DesignSupport("{'dbView':true,'imported':true,'generateDdl':false}") +@Table(name = "tms_v_terminal_report") +@Entity(name = "tms_TerminalReport") +public class TerminalReport extends BaseStringIdEntity { + private static final long serialVersionUID = -8873579277694377762L; + + @Id + @Column(name = "sn", nullable = false, length = 30) + protected String sn; + + @Column(name = "app_version", length = 30) + protected String appVersion; + + @Column(name = "auto_logon") + protected Boolean autoLogon; + + @Column(name = "beep_pin_keypad") + protected Boolean beepPinKeypad; + + @Column(name = "feature_card_verification") + protected Boolean featureCardVerification; + + @Column(name = "feature_contactless") + protected Boolean featureContactless; + + @Column(name = "feature_installment") + protected Boolean featureInstallment; + + @Column(name = "feature_manual_key_in") + protected Boolean featureManualKeyIn; + + @Column(name = "feature_qris") + protected Boolean featureQris; + + @Column(name = "feature_sale") + protected Boolean featureSale; + + @Column(name = "feature_sale_completion") + protected Boolean featureSaleCompletion; + + @Column(name = "feature_sale_fare_non_fare") + protected Boolean featureSaleFareNonFare; + + @Column(name = "feature_sale_redemption") + protected Boolean featureSaleRedemption; + + @Column(name = "feature_sale_tip") + protected Boolean featureSaleTip; + + @Column(name = "imei", length = 25) + protected String imei; + + @Column(name = "installment1_options", length = 20) + protected String installment1Options; + + @Column(name = "installment2_options", length = 20) + protected String installment2Options; + + @Column(name = "installment3_options", length = 20) + protected String installment3Options; + + @Column(name = "launcher_version", length = 30) + protected String launcherVersion; + + @Column(name = "merchant_id", length = 15) + protected String merchant; + + @Column(name = "merchant_name1", length = 30) + protected String merchantName1; + + @Column(name = "merchant_name2", length = 30) + protected String merchantName2; + + @Column(name = "merchant_name3", length = 30) + protected String merchantName3; + + @Column(name = "next_logon") + protected Integer nextLogon; + + @Column(name = "random_pin_keypad") + protected Boolean randomPinKeypad; + + @Lob + @Column(name = "state") + protected String state; + + @Column(name = "terminal_id", length = 8) + protected String terminal; + + @Column(name = "vfs_version") + protected String vfsVersion; + + @Column(name = "vfss_version") + protected String vfssVersion; + + @Column(name = "last_diagnostic_time") + protected Date lastDiagnosticTime; + + @Column(name = "last_heartbeat_time") + protected Date lastHeartbeatTime; + + @Column(name = "cell_name") + protected String cellName; + + @Column(name = "cell_type") + protected String cellType; + + @Column(name = "cell_strength") + protected Integer cellStrength; + + @Column(name = "wifi_name") + protected String wifiName; + + @Column(name = "wifi_strength") + protected Integer wifiStrength; + + @Column(name = "sam_available") + protected Boolean samAvailable; + + @Column(name = "push_logon") + protected Integer pushLogon; + + @Column(name = "host_report") + protected Boolean hostReport; + + @Column(name = "host_logging") + protected Boolean hostLogging; + + @Column(name = "apps") + protected String apps; + + public String getVfssVersion() { + return vfssVersion; + } + + public void setVfssVersion(String vfssVersion) { + this.vfssVersion = vfssVersion; + } + + public String getVfsVersion() { + return vfsVersion; + } + + public void setVfsVersion(String vfsVersion) { + this.vfsVersion = vfsVersion; + } + + public String getTerminal() { + return terminal; + } + + public void setTerminal(String terminal) { + this.terminal = terminal; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Boolean getRandomPinKeypad() { + return randomPinKeypad; + } + + public void setRandomPinKeypad(Boolean randomPinKeypad) { + this.randomPinKeypad = randomPinKeypad; + } + + public Integer getNextLogon() { + return nextLogon; + } + + public void setNextLogon(Integer nextLogon) { + this.nextLogon = nextLogon; + } + + public String getMerchantName3() { + return merchantName3; + } + + public void setMerchantName3(String merchantName3) { + this.merchantName3 = merchantName3; + } + + public String getMerchantName2() { + return merchantName2; + } + + public void setMerchantName2(String merchantName2) { + this.merchantName2 = merchantName2; + } + + public String getMerchantName1() { + return merchantName1; + } + + public void setMerchantName1(String merchantName1) { + this.merchantName1 = merchantName1; + } + + public String getMerchant() { + return merchant; + } + + public void setMerchant(String merchant) { + this.merchant = merchant; + } + + public String getLauncherVersion() { + return launcherVersion; + } + + public void setLauncherVersion(String launcherVersion) { + this.launcherVersion = launcherVersion; + } + + public String getInstallment3Options() { + return installment3Options; + } + + public void setInstallment3Options(String installment3Options) { + this.installment3Options = installment3Options; + } + + public String getInstallment2Options() { + return installment2Options; + } + + public void setInstallment2Options(String installment2Options) { + this.installment2Options = installment2Options; + } + + public String getInstallment1Options() { + return installment1Options; + } + + public void setInstallment1Options(String installment1Options) { + this.installment1Options = installment1Options; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public Boolean getFeatureSaleTip() { + return featureSaleTip; + } + + public void setFeatureSaleTip(Boolean featureSaleTip) { + this.featureSaleTip = featureSaleTip; + } + + public Boolean getFeatureSaleRedemption() { + return featureSaleRedemption; + } + + public void setFeatureSaleRedemption(Boolean featureSaleRedemption) { + this.featureSaleRedemption = featureSaleRedemption; + } + + public Boolean getFeatureSaleFareNonFare() { + return featureSaleFareNonFare; + } + + public void setFeatureSaleFareNonFare(Boolean featureSaleFareNonFare) { + this.featureSaleFareNonFare = featureSaleFareNonFare; + } + + public Boolean getFeatureSaleCompletion() { + return featureSaleCompletion; + } + + public void setFeatureSaleCompletion(Boolean featureSaleCompletion) { + this.featureSaleCompletion = featureSaleCompletion; + } + + public Boolean getFeatureSale() { + return featureSale; + } + + public void setFeatureSale(Boolean featureSale) { + this.featureSale = featureSale; + } + + public Boolean getFeatureQris() { + return featureQris; + } + + public void setFeatureQris(Boolean featureQris) { + this.featureQris = featureQris; + } + + public Boolean getFeatureManualKeyIn() { + return featureManualKeyIn; + } + + public void setFeatureManualKeyIn(Boolean featureManualKeyIn) { + this.featureManualKeyIn = featureManualKeyIn; + } + + public Boolean getFeatureInstallment() { + return featureInstallment; + } + + public void setFeatureInstallment(Boolean featureInstallment) { + this.featureInstallment = featureInstallment; + } + + public Boolean getFeatureContactless() { + return featureContactless; + } + + public void setFeatureContactless(Boolean featureContactless) { + this.featureContactless = featureContactless; + } + + public Boolean getFeatureCardVerification() { + return featureCardVerification; + } + + public void setFeatureCardVerification(Boolean featureCardVerification) { + this.featureCardVerification = featureCardVerification; + } + + public Boolean getBeepPinKeypad() { + return beepPinKeypad; + } + + public void setBeepPinKeypad(Boolean beepPinKeypad) { + this.beepPinKeypad = beepPinKeypad; + } + + public Boolean getAutoLogon() { + return autoLogon; + } + + public void setAutoLogon(Boolean autoLogon) { + this.autoLogon = autoLogon; + } + + public String getAppVersion() { + return appVersion; + } + + public void setAppVersion(String appVersion) { + this.appVersion = appVersion; + } + + @Override + public void setId(String id) { + this.sn = id; + } + + @Override + public String getId() { + return sn; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Date getLastDiagnosticTime() { + return lastDiagnosticTime; + } + + public void setLastDiagnosticTime(Date lastDiagnosticTime) { + this.lastDiagnosticTime = lastDiagnosticTime; + } + + public Date getLastHeartbeatTime() { + return lastHeartbeatTime; + } + + public void setLastHeartbeatTime(Date lastHeartbeatTime) { + this.lastHeartbeatTime = lastHeartbeatTime; + } + + public String getCellName() { + return cellName; + } + + public void setCellName(String cellName) { + this.cellName = cellName; + } + + public String getCellType() { + return cellType; + } + + public void setCellType(String cellType) { + this.cellType = cellType; + } + + public Integer getCellStrength() { + return cellStrength; + } + + public void setCellStrength(Integer cellStrength) { + this.cellStrength = cellStrength; + } + + public Integer getPushLogon() { + return pushLogon; + } + + public void setPushLogon(Integer pushLogon) { + this.pushLogon = pushLogon; + } + + public Boolean getHostReport() { + return hostReport; + } + + public void setHostReport(Boolean hostReport) { + this.hostReport = hostReport; + } + + public Boolean getHostLogging() { + return hostLogging; + } + + public void setHostLogging(Boolean hostLogging) { + this.hostLogging = hostLogging; + } + + public String getApps() { + return apps; + } + + public void setApps(String apps) { + this.apps = apps; + } + + public String getWifiName() { + return wifiName; + } + + public void setWifiName(String wifiName) { + this.wifiName = wifiName; + } + + public Integer getWifiStrength() { + return wifiStrength; + } + + public void setWifiStrength(Integer wifiStrength) { + this.wifiStrength = wifiStrength; + } + + public Boolean getSamAvailable() { + return samAvailable; + } + + public void setSamAvailable(Boolean samAvailable) { + this.samAvailable = samAvailable; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/VHeartBeat.java b/modules/global/src/com/cmobile/unifiedtms/entity/VHeartBeat.java new file mode 100644 index 0000000..a9ee61c --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/VHeartBeat.java @@ -0,0 +1,168 @@ +package com.cmobile.unifiedtms.entity; + +import com.haulmont.cuba.core.entity.BaseUuidEntity; +import com.haulmont.cuba.core.entity.Creatable; +import com.haulmont.cuba.core.entity.Versioned; +import com.haulmont.cuba.core.global.DesignSupport; + +import javax.persistence.*; +import java.util.Date; +import java.util.UUID; + +@DesignSupport("{'dbView':true,'imported':true,'generateDdl':false}") +@Table(name = "tms_v_terminal_heart_beat") +@Entity(name = "tms_VTerminalHeartBeat") +public class VHeartBeat extends BaseUuidEntity implements Versioned, Creatable { + private static final long serialVersionUID = -3539537453020368691L; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "create_ts") + protected Date createTs; + + @Column(name = "created_by", length = 50) + protected String createdBy; + + @Version + @Column(name = "version") + protected Integer version; + + @Column(name = "battery_percentage") + protected Integer batteryPercentage; + + @Column(name = "battery_temp") + protected Double batteryTemp; + + @Column(name = "latitude") + protected Double latitude; + + @Column(name = "longitude") + protected Double longitude; + + @Column(name = "terminal_sn", length = 30) + protected String terminalSn; + + @Column(name = "cell_name") + protected String cellName; + + @Column(name = "cell_type") + protected String cellType; + + @Column(name = "cell_strength") + protected Integer cellStrength; + + @Column(name = "wifi_name") + protected String wifiName; + + @Column(name = "wifi_strength") + protected Integer wifiStrength; + + @Override + public Date getCreateTs() { + return createTs; + } + + @Override + public void setCreateTs(Date createTs) { + this.createTs = createTs; + } + + @Override + public String getCreatedBy() { + return createdBy; + } + + @Override + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + @Override + public Integer getVersion() { + return version; + } + + @Override + public void setVersion(Integer version) { + this.version = version; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public String getTerminalSn() { + return terminalSn; + } + + public void setTerminalSn(String terminalSn) { + this.terminalSn = terminalSn; + } + + public String getCellName() { + return cellName; + } + + public void setCellName(String cellName) { + this.cellName = cellName; + } + + public String getCellType() { + return cellType; + } + + public void setCellType(String cellType) { + this.cellType = cellType; + } + + public Integer getCellStrength() { + return cellStrength; + } + + public void setCellStrength(Integer cellStrength) { + this.cellStrength = cellStrength; + } + + public String getWifiName() { + return wifiName; + } + + public void setWifiName(String wifiName) { + this.wifiName = wifiName; + } + + public Integer getWifiStrength() { + return wifiStrength; + } + + public void setWifiStrength(Integer wifiStrength) { + this.wifiStrength = wifiStrength; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/chartdata/CountryGrowth.java b/modules/global/src/com/cmobile/unifiedtms/entity/chartdata/CountryGrowth.java new file mode 100644 index 0000000..a78ef7b --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/chartdata/CountryGrowth.java @@ -0,0 +1,41 @@ +package com.cmobile.unifiedtms.entity.chartdata; + +import com.haulmont.chile.core.annotations.MetaClass; +import com.haulmont.chile.core.annotations.MetaProperty; +import com.haulmont.cuba.core.entity.BaseUuidEntity; + +@MetaClass(name = "tms_CountryGrowth") +public class CountryGrowth extends BaseUuidEntity { + @MetaProperty + protected String country; + + @MetaProperty + protected Double year2014; + + @MetaProperty + protected Double year2015; + + public Double getYear2015() { + return year2015; + } + + public void setYear2015(Double year2015) { + this.year2015 = year2015; + } + + public Double getYear2014() { + return year2014; + } + + public void setYear2014(Double year2014) { + this.year2014 = year2014; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/chartdata/PieChartData.java b/modules/global/src/com/cmobile/unifiedtms/entity/chartdata/PieChartData.java new file mode 100644 index 0000000..7e87053 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/chartdata/PieChartData.java @@ -0,0 +1,42 @@ +package com.cmobile.unifiedtms.entity.chartdata; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +public class PieChartData implements Serializable { + + private String id; + private String title; + private Map values = new HashMap<>(); + + public PieChartData(String id, String title) { + this.id = id; + this.title = title; + } + + public String getId() { + return id; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public Map getValues() { + return values; + } + + public void clearValues() { + values.clear(); + } + + public void addValue(String key, Object value) { + values.put(key, value); + } + +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/DeleteTaskActivity.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DeleteTaskActivity.java new file mode 100644 index 0000000..f8c5aca --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DeleteTaskActivity.java @@ -0,0 +1,37 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum DeleteTaskActivity implements EnumClass { + + INITIAL(0), + ACCEPTED(5), + NOT_STARTED(1), + DELETE_STARTED(2), + DELETE_SUCCESS(3), + DELETE_FAIL(4), + EXPIRED(99); + + private Integer id; + + DeleteTaskActivity(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static DeleteTaskActivity fromId(Integer id) { + for (DeleteTaskActivity at : DeleteTaskActivity.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskActivity.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskActivity.java new file mode 100644 index 0000000..bd66c67 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskActivity.java @@ -0,0 +1,40 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum DownloadTaskActivity implements EnumClass { + + INITIAL(0), + ACCEPTED(8), + NOT_STARTED(1), + DOWNLOAD_STARTED(2), + DOWNLOAD_SUCCESS(3), + DOWNLOAD_FAIL(4), + INSTALL_STARTED(5), + INSTALL_SUCCESS(6), + INSTALL_FAIL(7), + EXPIRED(99); + + private Integer id; + + DownloadTaskActivity(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static DownloadTaskActivity fromId(Integer id) { + for (DownloadTaskActivity at : DownloadTaskActivity.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskType.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskType.java new file mode 100644 index 0000000..95a594d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTaskType.java @@ -0,0 +1,32 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum DownloadTaskType implements EnumClass { + + APP_DOWNLOAD(1), + APP_DELETE(2); + + private Integer id; + + DownloadTaskType(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static DownloadTaskType fromId(Integer id) { + for (DownloadTaskType at : DownloadTaskType.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTimeType.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTimeType.java new file mode 100644 index 0000000..86ca157 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/DownloadTimeType.java @@ -0,0 +1,32 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum DownloadTimeType implements EnumClass { + + NEXT_CONTACT(1), + DATETIME(2); + + private Integer id; + + DownloadTimeType(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static DownloadTimeType fromId(Integer id) { + for (DownloadTimeType at : DownloadTimeType.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/ExportType.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/ExportType.java new file mode 100644 index 0000000..a812432 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/ExportType.java @@ -0,0 +1,32 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum ExportType implements EnumClass { + + CSV("CSV"), + XLS("XLS"); + + private String id; + + ExportType(String value) { + this.id = value; + } + + public String getId() { + return id; + } + + @Nullable + public static ExportType fromId(String id) { + for (ExportType at : ExportType.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/InstallationTimeType.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/InstallationTimeType.java new file mode 100644 index 0000000..168f466 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/InstallationTimeType.java @@ -0,0 +1,32 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum InstallationTimeType implements EnumClass { + + IMMEDIATE_AFTER_DOWNLOAD(1), + DATETIME(2); + + private Integer id; + + InstallationTimeType(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static InstallationTimeType fromId(Integer id) { + for (InstallationTimeType at : InstallationTimeType.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/ReportType.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/ReportType.java new file mode 100644 index 0000000..38d0f12 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/ReportType.java @@ -0,0 +1,34 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum ReportType implements EnumClass { + + DIAGNOSTIC_REPORT("Diagnostic Report"), + //ACTIVE_REPORT("Active Report"), + //OFFLINE_REPORT("Offline Report"), + ACK_REPORT("ACK Update Report"); + + private String id; + + ReportType(String value) { + this.id = value; + } + + public String getId() { + return id; + } + + @Nullable + public static ReportType fromId(String id) { + for (ReportType at : ReportType.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskNotificationType.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskNotificationType.java new file mode 100644 index 0000000..1d3e7aa --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskNotificationType.java @@ -0,0 +1,32 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum TaskNotificationType implements EnumClass { + + SILENT(1), + NEED_CONFIRMATION(2); + + private Integer id; + + TaskNotificationType(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static TaskNotificationType fromId(Integer id) { + for (TaskNotificationType at : TaskNotificationType.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskStatus.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskStatus.java new file mode 100644 index 0000000..6e79bcd --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TaskStatus.java @@ -0,0 +1,34 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum TaskStatus implements EnumClass { + + NOT_STARTED(1), + IN_PROGRESS(2), + CANCELLED(3), + DONE(4); + + private Integer id; + + TaskStatus(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static TaskStatus fromId(Integer id) { + for (TaskStatus at : TaskStatus.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/TerminalHeartBeatStatus.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TerminalHeartBeatStatus.java new file mode 100644 index 0000000..934ad01 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TerminalHeartBeatStatus.java @@ -0,0 +1,33 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum TerminalHeartBeatStatus implements EnumClass { + + ONLINE(1), + OFFLINE(2), + NOT_CONNECTED(3); + + private Integer id; + + TerminalHeartBeatStatus(Integer value) { + this.id = value; + } + + public Integer getId() { + return id; + } + + @Nullable + public static TerminalHeartBeatStatus fromId(Integer id) { + for (TerminalHeartBeatStatus at : TerminalHeartBeatStatus.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/TrxType.java b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TrxType.java new file mode 100644 index 0000000..bca0ab3 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/TrxType.java @@ -0,0 +1,34 @@ +package com.cmobile.unifiedtms.entity.enums; + +import com.haulmont.chile.core.datatypes.impl.EnumClass; + +import javax.annotation.Nullable; + + +public enum TrxType implements EnumClass { + + CREDIT("CREDIT"), + DEBIT("DEBIT"), + PREPAID("PREPAID"), + QRIS("QRIS"); + + private String id; + + TrxType(String value) { + this.id = value; + } + + public String getId() { + return id; + } + + @Nullable + public static TrxType fromId(String id) { + for (TrxType at : TrxType.values()) { + if (at.getId().equals(id)) { + return at; + } + } + return null; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/enums/messages.properties b/modules/global/src/com/cmobile/unifiedtms/entity/enums/messages.properties new file mode 100644 index 0000000..1dcc91d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/enums/messages.properties @@ -0,0 +1,45 @@ +DownloadTime=Download time +DownloadTimeType.NEXT_CONTACT=Next Contact +DownloadTimeType.DATETIME=Date & Time +InstallationTimeType=Installation time type +InstallationTimeType.IMMEDIATE_AFTER_DOWNLOAD=Immediate After Download +InstallationTimeType.DATETIME=Datetime +TaskNotificationType=Installation notification type +TaskNotificationType.SILENT=Silent +TaskNotificationType.NEED_CONFIRMATION=Need Cashier's Confirmation +DownloadTaskActivity=Download task activity +DownloadTaskActivity.INITIAL=Initial +DownloadTaskActivity.NOT_STARTED=Not Started +DownloadTaskActivity.DOWNLOAD_STARTED=Download Started +DownloadTaskActivity.DOWNLOAD_SUCCESS=Download Success +DownloadTaskActivity.DOWNLOAD_FAIL=Download Fail +DownloadTaskActivity.INSTALL_STARTED=Install Start +DownloadTaskActivity.INSTALL_SUCCESS=Install Success +DownloadTaskActivity.INSTALL_FAIL=Install Fail +DownloadTaskActivity.EXPIRED=Expired +TaskStatus=Download task status +TaskStatus.NOT_STARTED=Not Started +TaskStatus.IN_PROGRESS=In Progress +TaskStatus.CANCELLED=Cancelled +TaskStatus.DONE=Done +DownloadTaskType=Download task type +DownloadTaskType.APP_DOWNLOAD=App download +DownloadTaskType.APP_DELETE=App delete +TerminalHeartBeatStatus=Terminal heart beat status +TerminalHeartBeatStatus.ONLINE=Online +TerminalHeartBeatStatus.OFFLINE=Offline +TerminalHeartBeatStatus.NOT_CONNECTED=Not connected +DeleteTaskActivity=Delete task activity +DeleteTaskActivity.INITIAL=Initial +DeleteTaskActivity.NOT_STARTED=Not Started +DeleteTaskActivity.DELETE_STARTED=Delete Started +DeleteTaskActivity.DELETE_SUCCESS=Delete Success +DeleteTaskActivity.DELETE_FAIL=Delete Fail +DeleteTaskActivity.EXPIRED=Expired +ReportType=Report type +ReportType.ACTIVE_REPORT=Active report +ReportType.DIAGNOSTIC_REPORT=Diagnostic report +ReportType.OFFLINE_REPORT=Offline report +ReportType.ACK_REPORT=ACK report + + diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/messages.properties b/modules/global/src/com/cmobile/unifiedtms/entity/messages.properties new file mode 100644 index 0000000..c1a6ffb --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/messages.properties @@ -0,0 +1,358 @@ +Country=Country +Country.code=Code +Country.name=Name +States=States +States.name=Name +States.country=Country +City=City +City.states=States +City.name=Name +District=District +District.city=City +District.name=Name +MerchantType.name=Name +MerchantType.description=Description +Merchant=Merchant +Merchant.name=Name +Merchant.companyName=Company name +Merchant.district=District +Merchant.address=Address +Merchant.zipcode=Zipcode +Merchant.type=Type +Merchant.contactPersons=Contact persons +Terminal=Terminal +Terminal.sn=SN +Terminal.imei=Imei +Terminal.merchant=Merchant +Terminal.model=Model +DeviceModel=Device model +DeviceModel.vendorName=Vendor name +DeviceModel.vendorCountry=Vendor country +DeviceModel.model=Model +DeviceModel.modelInformation=Model information +TerminalGroup=Terminal group +TerminalGroup.name=Name +TerminalGroup.description=Description +TerminalGroup.terminals=Terminals +Terminal.group=Group +Terminal.profile=Profile +Application=Application +Application.packageName=Package name +Application.name=Name +Application.description=Description +Application.appVersion=App version +Application.icon=Icon +Application.apk=Apk +Application.uninstallable=Uninstallable +Application.companyName=Company name +Application.downloadTasks=Download tasks +ContactPerson=Contact person +ContactPerson.name=Name +ContactPerson.phone=Phone +ContactPerson.email=Email +ContactPerson.mobile=Mobile +ContactPerson.merchant=Merchant +ContactPerson.version=Version +DeviceProfile=Device profile +DeviceProfile.name=Name +DeviceProfile.heartbeatInterval=Heartbeat Interval +DeviceProfile.diagnosticInterval=Diagnostic Interval +DeviceProfile.maskHomeButton=Mask Home Button +DeviceProfile.maskStatusBar=Mask Status Bar +DeviceProfile.scheduleReboot=Schedule Reboot +DeviceProfile.scheduleRebootTime=Schedule Reboot Time +DeviceProfile.isDefault=Is Default +DeviceProfile.adminPassword=Admin password +DeviceProfile.relocationAlert=Relocation Alert +DeviceProfile.movingThreshold=Moving Threshold (m) +DeviceProfile.acquirers=Acquirers +HeartBeat=Heart Beat +HeartBeat.terminal=Terminal +HeartBeat.batteryTemp=Battery temp +HeartBeat.batteryPercentage=Battery percentage +HeartBeat.latitude=Latitude +HeartBeat.longitude=Longitude +HeartBeat.createTs=Create ts +HeartBeat.createdBy=Created by +HeartBeat.version=Version +DiagnosticInfo=Diagnostic info +DiagnosticInfo.meid=Meid +DiagnosticInfo.totalMemory=Total memory +DiagnosticInfo.availableMemory=Available memory +DiagnosticInfo.totalFlashMemory=Total flash memory +DiagnosticInfo.availableFlashMemory=Available flash memory +DiagnosticInfo.totalMobileData=Total mobile data +DiagnosticInfo.switchingTimes=Switching times +DiagnosticInfo.currentBootTime=Current boot times +DiagnosticInfo.totalBootTime=Total boot time +DiagnosticInfo.totalLengthPrinted=Total length printed +DiagnosticInfo.swipingCardTimes=Swiping card times +DiagnosticInfo.dipInsertingTimes=Dip inserting times +DiagnosticInfo.nfcCardReadingTimes=Nfc card reading times +DiagnosticInfo.frontCameraOpenTimes=Front camera open times +DiagnosticInfo.rearCameraOpenTimes=Rear camera open times +DiagnosticInfo.samAvailable=SAM Available +DiagnosticInfo.chargeTimes=Charge times +DiagnosticInfo.installedAppsString=Installed apps string +DownloadTask=Download task +DownloadTask.name=Name +DownloadTask.downloadTimeType=Download time type +DownloadTask.downloadTime=Download time +DownloadTask.installationTimeType=Installation time type +DownloadTask.installationTime=Installation time +DownloadTask.installationNotification=Installation notification +DownloadTask.applications=Applications +DownloadTask.terminalGroups=Terminal Groups +DownloadTaskLog=Download task log +DownloadTaskLog.task=Task +DownloadTaskLog.application=Application +DownloadTaskLog.activity=Activity +DownloadTaskLog.createTs=Create ts +DownloadTaskLog.createdBy=Created by +DownloadTaskLog.updateTs=Update ts +DownloadTaskLog.updatedBy=Updated by +DownloadTaskLog.version=Version +DownloadTaskLog.message=Message +DownloadTask.status=Status +DownloadTask.operations=Operation +TerminalLastHeartBeat=Terminal last heart beat +TerminalLastHeartBeat.createdBy=Created by +TerminalLastHeartBeat.latitude=Latitude +TerminalLastHeartBeat.batteryTemp=Battery temp +TerminalLastHeartBeat.createTs=Last Update +TerminalLastHeartBeat.batteryPercentage=Battery percentage +TerminalLastHeartBeat.terminalId=Terminal ID (UUID) +TerminalLastHeartBeat.terminalSn=Terminal SN +TerminalLastHeartBeat.terminalExtId=Terminal ID +TerminalLastHeartBeat.version=Version +TerminalLastHeartBeat.longitude=Longitude +TerminalLastHeartBeat.state=State +TerminalLastHeartBeat.cellName=Cell Name +TerminalLastHeartBeat.cellType=Cell Type +TerminalLastHeartBeat.cellStrength=Cell Strength +TerminalLastHeartBeat.wifiName=Wifi SSID +TerminalLastHeartBeat.wifiStrength=Wifi Strength +TerminalLastHeartBeat.updateTs=Update ts +TerminalLastHeartBeat.updatedBy=Updated by +TerminalLastDiagnosticInfo=Terminal last diagnostic info +TerminalLastDiagnosticInfo.availableFlashMemory=Available flash memory +TerminalLastDiagnosticInfo.meid=Meid +TerminalLastDiagnosticInfo.nfcCardReadingTimes=Nfc card reading times +TerminalLastDiagnosticInfo.latitude=Latitude +TerminalLastDiagnosticInfo.terminalSn=Terminal sn +TerminalLastDiagnosticInfo.rearCameraOpenTimes=Rear camera open times +TerminalLastDiagnosticInfo.totalBootTime=Total boot time +TerminalLastDiagnosticInfo.installedApps=Installed apps +TerminalLastDiagnosticInfo.batteryTemp=Battery temp +TerminalLastDiagnosticInfo.createTs=Create ts +TerminalLastDiagnosticInfo.longitude=Longitude +TerminalLastDiagnosticInfo.switchingTimes=Switching times +TerminalLastDiagnosticInfo.swipingCardTimes=Swiping card times +TerminalLastDiagnosticInfo.terminal=Terminal +TerminalLastDiagnosticInfo.totalLengthPrinted=Total length printed +TerminalLastDiagnosticInfo.totalMobileData=Total mobile data +TerminalLastDiagnosticInfo.totalMemory=Total memory +TerminalLastDiagnosticInfo.availableMemory=Available memory +TerminalLastDiagnosticInfo.currentBootTime=Current boot time +TerminalLastDiagnosticInfo.createdBy=Created by +TerminalLastDiagnosticInfo.chargeTimes=Charge times +TerminalLastDiagnosticInfo.totalFlashMemory=Total flash memory +TerminalLastDiagnosticInfo.batteryPercentage=Battery percentage +TerminalLastDiagnosticInfo.dipInsertingTimes=Dip inserting times +TerminalLastDiagnosticInfo.frontCameraOpenTimes=Front camera open times +TerminalLastDiagnosticInfo.terminalExtId=TID +ApplicationSimple=Application simple +ApplicationSimple.appName=App name +ApplicationSimple.packageName=Package name +ApplicationSimple.appVersion=App version +ApplicationSimple.diagnosticInfo=Diagnostic info +ApplicationSimple.deleteTasks=Delete tasks +Application.downloadUrl=Download url +Application.checksum=Checksum +DeleteTask=Delete task +DeleteTask.name=Name +DeleteTask.deleteTime=Delete time +DeleteTask.applications=Applications +DeleteTask.terminalGroups=Terminal Groups +DeleteTask.operations=Operation +DeleteTaskLog=Download task log +DeleteTaskLog.task=Task +DeleteTaskLog.application=Application +DeleteTaskLog.activity=Activity +DeleteTaskLog.createTs=Create ts +DeleteTaskLog.createdBy=Created by +DeleteTaskLog.updateTs=Update ts +DeleteTaskLog.updatedBy=Updated by +DeleteTaskLog.version=Version +DeleteTaskLog.message=Message +DeleteTask.status=Status +Aid=Aid +Aid.clOptions=Cl options +Aid.targetPercentage=Target percentage +Aid.remark=Remark +Aid.threshold=Threshold +Aid.txnType=Txn type +Aid.maxTargetPercentage=Max target percentage +Aid.deletedBy=Deleted by +Aid.floorLimit=Floor limit +Aid.deleteTs=Delete ts +Aid.clFloorLimit=Cl floor limit +Aid.createTs=Create ts +Aid.tacDefault=Tac default +Aid.clKernelToUse=Cl kernel to use +Aid.updatedBy=Updated by +Aid.aidPriority=Aid priority +Aid.tacOnline=Tac online +Aid.categoryCode=Category code +Aid.version=Version +Aid.appSelect=App select +Aid.ddol=Ddol +Aid.aidVersion=Aid version +Aid.tacDenial=Tac denial +Aid.createdBy=Created by +Aid.trxType9C=Trx type9c +Aid.name=Name +Aid.tdol=Tdol +Aid.updateTs=Update ts +Aid.aid=Aid +Aid.clCvmLimit=Cl cvm limit +Aid.clTrxLimit=Cl trx limit +Card.updatedBy=Updated by +Card.version=Version +Card.deletedBy=Deleted by +Card.deleteTs=Delete ts +Card.createdBy=Created by +Card.createTs=Create ts +Card.updateTs=Update ts +TerminalLink=Terminal link +TerminalLink.terminal=Terminal +TerminalLink.terminalExt=Terminal ext +Terminal.terminalLink=Terminal link +Terminal.importDefault=Import default + +TerminalReport=Terminal Report +TerminalReport.featureManualKeyIn=Manual Key In +TerminalReport.appVersion=App Version +TerminalReport.autoLogon=Auto Logon +TerminalReport.merchantName2=Merchant Address +TerminalReport.featureSaleFareNonFare=Sale Fare Non Fare +TerminalReport.merchantName1=Merchant +TerminalReport.randomPinKeypad=Random Pin Keypad +TerminalReport.nextLogon=Next Logon (In Hours) +TerminalReport.featureSaleTip=Sale Tip +TerminalReport.launcherVersion=Launcher Version +TerminalReport.updateTs=Last Update +TerminalReport.installment2Options=Installment Plan 2 +TerminalReport.installment3Options=Installment Plan 3 +TerminalReport.featureSale=Sale +TerminalReport.sn=Serial Number +TerminalReport.state=State +TerminalReport.featureCardVerification=Card Verification +TerminalReport.installment1Options=Installment Plan 1 +TerminalReport.featureSaleRedemption=Sale Redemption +TerminalReport.featureContactless=Contactless +TerminalReport.featureQris=QRIS +TerminalReport.merchant=Merchant ID +TerminalReport.terminal=Terminal ID +TerminalReport.beepPinKeypad=Beep Pin Keypad +TerminalReport.merchantName3=Kab & Kodepos +TerminalReport.featureInstallment=Installment +TerminalReport.imei=IMEI +TerminalReport.featureSaleCompletion=Sale Completion +TerminalReport.vfsVersion=VF Service +TerminalReport.vfssVersion=VFSSystem Service +TerminalReport.lastDiagnosticTime=Last Update Diagnostic +TerminalReport.lastHeartbeatTime=Last Update Heartbeat +TerminalReport.cellName=Cell Name +TerminalReport.cellType=Cell Type +TerminalReport.cellStrength=Cell Strength +TerminalReport.wifiName=Wifi SSID +TerminalReport.wifiStrength=Wifi Strength +TerminalReport.samAvailable=SAM Available +TerminalGroupImport=Terminal group import +TerminalGroupImport.sn=Sn +TerminalGroupImport.tid=Tid +TerminalGroupImport.snFound=Sn found +TerminalGroupImport.tidFound=Tid found +ExportType.CSV = CSV +ExportType.XLS = XLS +TrxType.DEBIT = DEBIT +TrxType.CREDIT = CREDIT +TrxType.PREPAID = PREPAID +TrxType.QRIS = QRIS +ResponseCode.type=Trx Type +ResponseCode.code=RC +ResponseCode.desc=Description +DeviceProfileApp.packageName=Package Name +DeviceProfileApp.profile=Profile +DeviceProfile.apps=Apps +DeviceProfile.frontApp=Front Application +DeviceProfile.hostReport=Host Report +DeviceProfile.hostReportUrl=Host Report URL +DeviceProfile.hostReportApiKey=Host Report API Key +DeviceProfile.hostReportTimeout=Host Report Timeout +DeviceProfile.hostLogging=Host Logging +DeviceProfile.hostLoggingUrl=Host Logging URL +DeviceProfile.hostLoggingApiKey=Host Logging API Key +DeviceProfile.hostLoggingTimeout=Host Logging Timeout +DeviceProfile.autoStartApp=Auto start app +HeartbeatSummary=Heartbeat Summary +HeartbeatSummary.groupName=Group Vendor +HeartbeatSummary.retailTotal=Total +HeartbeatSummary.retailTotal1H=<1 hour +HeartbeatSummary.retailTotal1D=1-24 hours +HeartbeatSummary.retailTotalToday=Today +HeartbeatSummary.retailTotal7D=1-7 days +HeartbeatSummary.retailTotalMore7D=>7 days +HeartbeatSummary.retailTotalSigma=Σ +HeartbeatSummary.retailReliability=Reliability (%) +HeartbeatSummary.chainTotal=Total +HeartbeatSummary.chainTotal1H=<1 hour +HeartbeatSummary.chainTotal1D=1-24 hours +HeartbeatSummary.chainTotalToday=Today +HeartbeatSummary.chainTotal7D=1-7 days +HeartbeatSummary.chainTotalMore7D=>7 days +HeartbeatSummary.chainTotalSigma=Σ +HeartbeatSummary.chainReliability=Reliability (%) +HeartbeatSummary.updatedBy=Generated By +HeartbeatSummary.updateTs=Generate Time +VHeartBeat=Terminal Heart Beat +VHeartBeat.createdBy=Created by +VHeartBeat.latitude=Latitude +VHeartBeat.batteryTemp=Battery Temp +VHeartBeat.createTs=Last Update +VHeartBeat.batteryPercentage=Battery Percentage +VHeartBeat.terminalSn=Terminal SN +VHeartBeat.version=Version +VHeartBeat.longitude=Longitude +VHeartBeat.cellName=Cell Name +VHeartBeat.cellType=Cell Type +VHeartBeat.cellStrength=Cell Strength +VHeartBeat.wifiName=Wifi SSID +VHeartBeat.wifiStrength=Wifi Strength + + +TerminalProfiling=Terminal Profiling +TerminalProfiling.createdBy=Created by +TerminalProfiling.createTs=Create ts +TerminalProfiling.version=Version +TerminalProfiling.file=File +TerminalProfiling.items=Items +TerminalProfilingItem=Terminal Profiling Item +TerminalProfilingItem.createdBy=Created by +TerminalProfilingItem.createTs=Create ts +TerminalProfilingItem.sn=SN +TerminalProfilingItem.imei=Imei +TerminalProfilingItem.modelName=Model Name +TerminalProfilingItem.merchantName=Merchant Name +TerminalProfilingItem.profileName=Profile Name +TerminalProfilingItem.groupNames=Group Names +TerminalProfilingItem.terminalIdTemplate=Terminal Id Template +TerminalProfilingItem.terminalId=Terminal Id +TerminalProfilingItem.merchantId=Merchant Id +TerminalProfilingItem.merchantName1=Merchant Name 1 +TerminalProfilingItem.merchantName2=Merchant Name 2 +TerminalProfilingItem.merchantName3=Merchant Name 3 +TerminalProfilingItem.merchantName4=Merchant Name 4 +TerminalProfilingItem.merchantName5=Merchant Name 5 + diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/misc/CellInfo.java b/modules/global/src/com/cmobile/unifiedtms/entity/misc/CellInfo.java new file mode 100644 index 0000000..9579bc7 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/misc/CellInfo.java @@ -0,0 +1,55 @@ +package com.cmobile.unifiedtms.entity.misc; + +import javax.annotation.Generated; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +@Generated("jsonschema2pojo") +public class CellInfo { + + @SerializedName("name") + @Expose + private String name; + @SerializedName("cid") + @Expose + private String cid; + @SerializedName("type") + @Expose + private String type; + @SerializedName("strength") + @Expose + private Integer strength; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCid() { + return cid; + } + + public void setCid(String cid) { + this.cid = cid; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Integer getStrength() { + return strength; + } + + public void setStrength(Integer strength) { + this.strength = strength; + } + +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/misc/ExpirableObject.java b/modules/global/src/com/cmobile/unifiedtms/entity/misc/ExpirableObject.java new file mode 100644 index 0000000..1c4ecd7 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/misc/ExpirableObject.java @@ -0,0 +1,26 @@ +package com.cmobile.unifiedtms.entity.misc; + +public class ExpirableObject { + + private long storageTime = -1L; + private long expiryTime = -1L; + private T object; + + public ExpirableObject(T object, long expiryTime) { + this.object = object; + this.expiryTime = expiryTime; + this.storageTime = System.currentTimeMillis(); + } + + public T getObject() { + if(!isExpired()) { + return object; + } + return null; + } + + public boolean isExpired() { + long current = System.currentTimeMillis(); + return (current > (this.storageTime + this.expiryTime)); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/misc/FileDownloadWrapper.java b/modules/global/src/com/cmobile/unifiedtms/entity/misc/FileDownloadWrapper.java new file mode 100644 index 0000000..09b7d97 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/misc/FileDownloadWrapper.java @@ -0,0 +1,36 @@ +package com.cmobile.unifiedtms.entity.misc; + +import java.io.Serializable; + +public class FileDownloadWrapper implements Serializable { + + private String downloadUrl; + private String checksum; + private boolean uploaded; + + public FileDownloadWrapper() {} + + public boolean isUploaded() { + return uploaded; + } + + public void setUploaded(boolean uploaded) { + this.uploaded = uploaded; + } + + public String getDownloadUrl() { + return downloadUrl; + } + + public void setDownloadUrl(String downloadUrl) { + this.downloadUrl = downloadUrl; + } + + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalGroupImportObjectWrapper.java b/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalGroupImportObjectWrapper.java new file mode 100644 index 0000000..fee7b1a --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalGroupImportObjectWrapper.java @@ -0,0 +1,60 @@ +package com.cmobile.unifiedtms.entity.misc; + +import com.cmobile.unifiedtms.entity.Terminal; +import com.cmobile.unifiedtms.entity.TerminalLink; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class TerminalGroupImportObjectWrapper implements Serializable { + + private String tid; + private String sn; + private Terminal terminal; + private boolean snFound; + private boolean tidFound; + + public TerminalGroupImportObjectWrapper() { + } + + public String getTid() { + return tid; + } + + public void setTid(String tid) { + this.tid = tid; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Terminal getTerminal() { + return terminal; + } + + public void setTerminal(Terminal terminal) { + this.terminal = terminal; + } + + public boolean isSnFound() { + return snFound; + } + + public void setSnFound(boolean snFound) { + this.snFound = snFound; + } + + public boolean isTidFound() { + return tidFound; + } + + public void setTidFound(boolean tidFound) { + this.tidFound = tidFound; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalImporterObjectWrapper.java b/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalImporterObjectWrapper.java new file mode 100644 index 0000000..8ab4d03 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalImporterObjectWrapper.java @@ -0,0 +1,30 @@ +package com.cmobile.unifiedtms.entity.misc; + +import com.cmobile.unifiedtms.entity.TerminalLink; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class TerminalImporterObjectWrapper implements Serializable { + + private List terminalLinks; + + public TerminalImporterObjectWrapper() { + } + + public TerminalImporterObjectWrapper(List terminalLinks) { + this.terminalLinks = terminalLinks; + } + + public List getTerminalLinks() { + if(terminalLinks == null) { + terminalLinks = new ArrayList<>(); + } + return terminalLinks; + } + + public void setTerminalLinks(List terminalLinks) { + this.terminalLinks = terminalLinks; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalUpdateCacheObj.java b/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalUpdateCacheObj.java new file mode 100644 index 0000000..957f98c --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/misc/TerminalUpdateCacheObj.java @@ -0,0 +1,61 @@ +package com.cmobile.unifiedtms.entity.misc; + +import java.io.Serializable; +import java.util.Date; +import java.util.concurrent.CountDownLatch; + +public class TerminalUpdateCacheObj implements Serializable { + + private String sn; + private CountDownLatch countDownLatch; + private String status; // started, ongoing, finished + private String lastStepName; + private Date createdTime; + private Date lastStepUpdateTime; + + public TerminalUpdateCacheObj(String sn) { + this.sn = sn; + this.countDownLatch = new CountDownLatch(5); + this.status = "Started"; + this.createdTime = new Date(); + } + + public String getSn() { + return sn; + } + + public CountDownLatch getCountDownLatch() { + return countDownLatch; + } + + public String getStatus() { + return status; + } + + public void continueStep(String stepName) { + if(stepName != null && !stepName.equals(this.lastStepName)) { + this.lastStepName = stepName; + this.lastStepUpdateTime = new Date(); + this.countDownLatch.countDown(); + if(this.countDownLatch.getCount() == 0) { + this.considerDone(); + } + } + } + + public void considerDone() { + this.status = "Finished"; + } + + public String getLastStepName() { + return lastStepName; + } + + public Date getCreatedTime() { + return createdTime; + } + + public Date getLastStepUpdateTime() { + return lastStepUpdateTime; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/DiagnosticInfo.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/DiagnosticInfo.java new file mode 100644 index 0000000..ead11de --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/DiagnosticInfo.java @@ -0,0 +1,214 @@ +package com.cmobile.unifiedtms.entity.restmodel; + +import java.util.HashMap; +import java.util.Map; + +public class DiagnosticInfo { + + private String imei; + private String meid; + private Double batteryTemp; + private Integer batteryPercentage; + private String totalMemory; + private String availableMemory; + private String totalFlashMemory; + private String availableFlashMemory; + private String totalMobileData; + private String switchingTimes; + private String currentBootTime; + private String totalBootTime; + private String totalLengthPrinted; + private Integer swipingCardTimes; + private Integer dipInsertingTimes; + private Integer nfcCardReadingTimes; + private Integer frontCameraOpenTimes; + private Integer rearCameraOpenTimes; + private Integer chargeTimes; + private Map additionalProperties = new HashMap(); + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public String getMeid() { + return meid; + } + + public void setMeid(String meid) { + this.meid = meid; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + public String getTotalMemory() { + return totalMemory; + } + + public void setTotalMemory(String totalMemory) { + this.totalMemory = totalMemory; + } + + public String getAvailableMemory() { + return availableMemory; + } + + public void setAvailableMemory(String availableMemory) { + this.availableMemory = availableMemory; + } + + public String getTotalFlashMemory() { + return totalFlashMemory; + } + + public void setTotalFlashMemory(String totalFlashMemory) { + this.totalFlashMemory = totalFlashMemory; + } + + public String getAvailableFlashMemory() { + return availableFlashMemory; + } + + public void setAvailableFlashMemory(String availableFlashMemory) { + this.availableFlashMemory = availableFlashMemory; + } + + public String getTotalMobileData() { + return totalMobileData; + } + + public void setTotalMobileData(String totalMobileData) { + this.totalMobileData = totalMobileData; + } + + public String getSwitchingTimes() { + return switchingTimes; + } + + public void setSwitchingTimes(String switchingTimes) { + this.switchingTimes = switchingTimes; + } + + public String getCurrentBootTime() { + return currentBootTime; + } + + public void setCurrentBootTime(String currentBootTime) { + this.currentBootTime = currentBootTime; + } + + public String getTotalBootTime() { + return totalBootTime; + } + + public void setTotalBootTime(String totalBootTime) { + this.totalBootTime = totalBootTime; + } + + public String getTotalLengthPrinted() { + return totalLengthPrinted; + } + + public void setTotalLengthPrinted(String totalLengthPrinted) { + this.totalLengthPrinted = totalLengthPrinted; + } + + public Integer getSwipingCardTimes() { + return swipingCardTimes; + } + + public void setSwipingCardTimes(Integer swipingCardTimes) { + this.swipingCardTimes = swipingCardTimes; + } + + public Integer getDipInsertingTimes() { + return dipInsertingTimes; + } + + public void setDipInsertingTimes(Integer dipInsertingTimes) { + this.dipInsertingTimes = dipInsertingTimes; + } + + public Integer getNfcCardReadingTimes() { + return nfcCardReadingTimes; + } + + public void setNfcCardReadingTimes(Integer nfcCardReadingTimes) { + this.nfcCardReadingTimes = nfcCardReadingTimes; + } + + public Integer getFrontCameraOpenTimes() { + return frontCameraOpenTimes; + } + + public void setFrontCameraOpenTimes(Integer frontCameraOpenTimes) { + this.frontCameraOpenTimes = frontCameraOpenTimes; + } + + public Integer getRearCameraOpenTimes() { + return rearCameraOpenTimes; + } + + public void setRearCameraOpenTimes(Integer rearCameraOpenTimes) { + this.rearCameraOpenTimes = rearCameraOpenTimes; + } + + public Integer getChargeTimes() { + return chargeTimes; + } + + public void setChargeTimes(Integer chargeTimes) { + this.chargeTimes = chargeTimes; + } + + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + @Override + public String toString() { + return "DiagnosticInfo{" + + "imei='" + imei + '\'' + + ", meid='" + meid + '\'' + + ", batteryTemp=" + batteryTemp + + ", batteryPercentage=" + batteryPercentage + + ", totalMemory='" + totalMemory + '\'' + + ", availableMemory='" + availableMemory + '\'' + + ", totalFlashMemory='" + totalFlashMemory + '\'' + + ", availableFlashMemory='" + availableFlashMemory + '\'' + + ", totalMobileData='" + totalMobileData + '\'' + + ", switchingTimes='" + switchingTimes + '\'' + + ", currentBootTime='" + currentBootTime + '\'' + + ", totalBootTime='" + totalBootTime + '\'' + + ", totalLengthPrinted='" + totalLengthPrinted + '\'' + + ", swipingCardTimes=" + swipingCardTimes + + ", dipInsertingTimes=" + dipInsertingTimes + + ", nfcCardReadingTimes=" + nfcCardReadingTimes + + ", frontCameraOpenTimes=" + frontCameraOpenTimes + + ", rearCameraOpenTimes=" + rearCameraOpenTimes + + ", chargeTimes=" + chargeTimes + + ", additionalProperties=" + additionalProperties + + '}'; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/HeartBeatRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/HeartBeatRequest.java new file mode 100644 index 0000000..33730c1 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/HeartBeatRequest.java @@ -0,0 +1,87 @@ +package com.cmobile.unifiedtms.entity.restmodel; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +public class HeartBeatRequest { + + private String reqId; + private String requestTime; + private String deviceSn; + private DiagnosticInfo diagnosticInfo; + private LocationInfo locationInfo; + private Map additionalProperties = new HashMap(); + + public String getReqId() { + return reqId; + } + + public void setReqId(String reqId) { + this.reqId = reqId; + } + + public String getRequestTime() { + return requestTime; + } + + public void setRequestTime(String requestTime) { + this.requestTime = requestTime; + } + + public String getDeviceSn() { + return deviceSn; + } + + public void setDeviceSn(String deviceSn) { + this.deviceSn = deviceSn; + } + + public DiagnosticInfo getDiagnosticInfo() { + return diagnosticInfo; + } + + public void setDiagnosticInfo(DiagnosticInfo diagnosticInfo) { + this.diagnosticInfo = diagnosticInfo; + } + + public LocationInfo getLocationInfo() { + return locationInfo; + } + + public void setLocationInfo(LocationInfo locationInfo) { + this.locationInfo = locationInfo; + } + + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HeartBeatRequest that = (HeartBeatRequest) o; + return reqId.equals(that.reqId); + } + + @Override + public int hashCode() { + return Objects.hash(reqId); + } + + @Override + public String toString() { + return "HeartBeatRequest{" + + "reqId='" + reqId + '\'' + + ", requestTime='" + requestTime + '\'' + + ", deviceSn='" + deviceSn + '\'' + + ", diagnosticInfo=" + diagnosticInfo + + ", locationInfo=" + locationInfo + + ", additionalProperties=" + additionalProperties + + '}'; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/LocationInfo.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/LocationInfo.java new file mode 100644 index 0000000..7d4844f --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/LocationInfo.java @@ -0,0 +1,43 @@ +package com.cmobile.unifiedtms.entity.restmodel; + +import java.util.HashMap; +import java.util.Map; +public class LocationInfo { + + private Double lat; + private Double lng; + private Map additionalProperties = new HashMap(); + + public Double getLat() { + return lat; + } + + public void setLat(Double lat) { + this.lat = lat; + } + + public Double getLng() { + return lng; + } + + public void setLng(Double lng) { + this.lng = lng; + } + + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } + + @Override + public String toString() { + return "LocationInfo{" + + "lat=" + lat + + ", lng=" + lng + + ", additionalProperties=" + additionalProperties + + '}'; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AckParameterRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AckParameterRequest.java new file mode 100644 index 0000000..80dc8e5 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AckParameterRequest.java @@ -0,0 +1,76 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; + +public class AckParameterRequest implements Serializable { + + private String sn; + private Object lastInitTime; + private Object syncStartTime; + private Object syncEndTime; + private Integer retryCount; + private String status; + + public AckParameterRequest() { + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Object getLastInitTime() { + return lastInitTime; + } + + public void setLastInitTime(Object lastInitTime) { + this.lastInitTime = lastInitTime; + } + + public Object getSyncStartTime() { + return syncStartTime; + } + + public void setSyncStartTime(Object syncStartTime) { + this.syncStartTime = syncStartTime; + } + + public Object getSyncEndTime() { + return syncEndTime; + } + + public void setSyncEndTime(Object syncEndTime) { + this.syncEndTime = syncEndTime; + } + + public Integer getRetryCount() { + return retryCount; + } + + public void setRetryCount(Integer retryCount) { + this.retryCount = retryCount; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + public String toString() { + return "AckParameterRequest{" + + "sn='" + sn + '\'' + + ", lastInitTime=" + lastInitTime + + ", syncStartTime=" + syncStartTime + + ", syncEndTime=" + syncEndTime + + ", retryCount=" + retryCount + + ", status=" + status + + '}'; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddApplicationRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddApplicationRequest.java new file mode 100644 index 0000000..9e6b49d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddApplicationRequest.java @@ -0,0 +1,91 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import com.cmobile.unifiedtms.entity.restmodel.result.data.DeviceModelSimple; +import com.cmobile.unifiedtms.entity.restmodel.result.data.DeviceProfileSimple; +import com.cmobile.unifiedtms.entity.restmodel.result.data.MerchantSimple; +import com.cmobile.unifiedtms.entity.restmodel.result.data.TerminalGroupSimple; + +import java.io.Serializable; +import java.util.List; +import java.util.UUID; + +public class AddApplicationRequest implements Serializable { + + // will be extracted from apkFileId + private String packageName; + private String companyName; + private String name; + private String description; + // will be extracted from apkFileId + private String appVersion; + private UUID iconFileId; + private UUID apkFileId; + private Boolean uninstallable; + + public AddApplicationRequest() { + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAppVersion() { + return appVersion; + } + + public void setAppVersion(String appVersion) { + this.appVersion = appVersion; + } + + public UUID getIconFileId() { + return iconFileId; + } + + public void setIconFileId(UUID iconFileId) { + this.iconFileId = iconFileId; + } + + public UUID getApkFileId() { + return apkFileId; + } + + public void setApkFileId(UUID apkFileId) { + this.apkFileId = apkFileId; + } + + public Boolean getUninstallable() { + return uninstallable; + } + + public void setUninstallable(Boolean uninstallable) { + this.uninstallable = uninstallable; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddDownloadTaskRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddDownloadTaskRequest.java new file mode 100644 index 0000000..b8b4a17 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddDownloadTaskRequest.java @@ -0,0 +1,82 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +public class AddDownloadTaskRequest implements Serializable { + + private String name; + private Integer downloadTimeType; + private String downloadTime; + private Integer installationTimeType; + private String installationTime; + private Integer installationNotification; + private List applicationIds; + private List terminalGroupIds; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getDownloadTimeType() { + return downloadTimeType; + } + + public void setDownloadTimeType(Integer downloadTimeType) { + this.downloadTimeType = downloadTimeType; + } + + public String getDownloadTime() { + return downloadTime; + } + + public void setDownloadTime(String downloadTime) { + this.downloadTime = downloadTime; + } + + public Integer getInstallationTimeType() { + return installationTimeType; + } + + public void setInstallationTimeType(Integer installationTimeType) { + this.installationTimeType = installationTimeType; + } + + public String getInstallationTime() { + return installationTime; + } + + public void setInstallationTime(String installationTime) { + this.installationTime = installationTime; + } + + public Integer getInstallationNotification() { + return installationNotification; + } + + public void setInstallationNotification(Integer installationNotification) { + this.installationNotification = installationNotification; + } + + public List getApplicationIds() { + return applicationIds; + } + + public void setApplicationIds(List applicationIds) { + this.applicationIds = applicationIds; + } + + public List getTerminalGroupIds() { + return terminalGroupIds; + } + + public void setTerminalGroupIds(List terminalGroupIds) { + this.terminalGroupIds = terminalGroupIds; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddProfileRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddProfileRequest.java new file mode 100644 index 0000000..85c9298 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddProfileRequest.java @@ -0,0 +1,13 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.List; +import java.util.UUID; + +public class AddProfileRequest implements Serializable { + + private String name; + + public AddProfileRequest() { + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalGroupRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalGroupRequest.java new file mode 100644 index 0000000..cdfd5f9 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalGroupRequest.java @@ -0,0 +1,42 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +public class AddTerminalGroupRequest implements Serializable { + + private String name; + private String description; + private List terminals; + + public AddTerminalGroupRequest() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getTerminals() { + if(terminals == null) { + terminals = Collections.EMPTY_LIST; + } + return terminals; + } + + public void setTerminals(List terminals) { + this.terminals = terminals; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalRequest.java new file mode 100644 index 0000000..72aa47e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/AddTerminalRequest.java @@ -0,0 +1,72 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import com.cmobile.unifiedtms.entity.DeviceProfile; +import com.cmobile.unifiedtms.entity.restmodel.result.data.DeviceModelSimple; +import com.cmobile.unifiedtms.entity.restmodel.result.data.DeviceProfileSimple; +import com.cmobile.unifiedtms.entity.restmodel.result.data.MerchantSimple; +import com.cmobile.unifiedtms.entity.restmodel.result.data.TerminalGroupSimple; + +import java.io.Serializable; +import java.util.List; +import java.util.UUID; + +public class AddTerminalRequest implements Serializable { + + private String sn; + private String imei; + private UUID merchantId; + private UUID modelId; + private UUID profileId; + private List groupIds; + + public AddTerminalRequest() { + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public UUID getMerchantId() { + return merchantId; + } + + public void setMerchantId(UUID merchantId) { + this.merchantId = merchantId; + } + + public UUID getModelId() { + return modelId; + } + + public void setModelId(UUID modelId) { + this.modelId = modelId; + } + + public UUID getProfileId() { + return profileId; + } + + public void setProfileId(UUID profileId) { + this.profileId = profileId; + } + + public List getGroupIds() { + return groupIds; + } + + public void setGroupIds(List groupIds) { + this.groupIds = groupIds; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/CheckUpdateRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/CheckUpdateRequest.java new file mode 100644 index 0000000..5142c65 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/CheckUpdateRequest.java @@ -0,0 +1,37 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.Date; + +public class CheckUpdateRequest implements Serializable { + + private String sn; + private Object lastInitTime; + + public CheckUpdateRequest() { + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Object getLastInitTime() { + return lastInitTime; + } + + public void setLastInitTime(Object lastInitTime) { + this.lastInitTime = lastInitTime; + } + + @Override + public String toString() { + return "CheckUpdateRequest{" + + "sn='" + sn + '\'' + + ", lastInitTime=" + lastInitTime + + '}'; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DeleteRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DeleteRequest.java new file mode 100644 index 0000000..36d7358 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DeleteRequest.java @@ -0,0 +1,20 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.UUID; + +public class DeleteRequest implements Serializable { + + private UUID id; + + public DeleteRequest() { + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DetailRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DetailRequest.java new file mode 100644 index 0000000..fc1dc29 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/DetailRequest.java @@ -0,0 +1,20 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.UUID; + +public class DetailRequest implements Serializable { + + private UUID id; + + public DetailRequest() { + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalGroupRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalGroupRequest.java new file mode 100644 index 0000000..56e938f --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalGroupRequest.java @@ -0,0 +1,18 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.util.UUID; + +public class EditTerminalGroupRequest extends AddTerminalGroupRequest { + + private UUID id; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public EditTerminalGroupRequest() {} +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalRequest.java new file mode 100644 index 0000000..1944a0e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/EditTerminalRequest.java @@ -0,0 +1,18 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.util.UUID; + +public class EditTerminalRequest extends AddTerminalRequest { + + private UUID id; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public EditTerminalRequest() {} +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/InitProfileRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/InitProfileRequest.java new file mode 100644 index 0000000..29e7e2b --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/InitProfileRequest.java @@ -0,0 +1,37 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.Date; + +public class InitProfileRequest implements Serializable { + + private String sn; + private Date lastInitTime; + + public InitProfileRequest() { + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public Date getLastInitTime() { + return lastInitTime; + } + + public void setLastInitTime(Date lastInitTime) { + this.lastInitTime = lastInitTime; + } + + @Override + public String toString() { + return "InitProfileRequest{" + + "sn='" + sn + '\'' + + ", lastInitTime=" + lastInitTime + + '}'; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/PaginatedRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/PaginatedRequest.java new file mode 100644 index 0000000..a72d2e8 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/PaginatedRequest.java @@ -0,0 +1,37 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; + +public class PaginatedRequest implements Serializable { + + private int pageNum = -1; + private int totalPerPage = 10; + + public PaginatedRequest() { + } + + public PaginatedRequest(int pageNum) { + this.pageNum = pageNum; + } + + public PaginatedRequest(int pageNum, int totalPerPage) { + this.pageNum = pageNum; + this.totalPerPage = totalPerPage; + } + + public int getPageNum() { + return pageNum; + } + + public void setPageNum(int pageNum) { + this.pageNum = pageNum; + } + + public int getTotalPerPage() { + return totalPerPage; + } + + public void setTotalPerPage(int totalPerPage) { + this.totalPerPage = totalPerPage; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalAssignRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalAssignRequest.java new file mode 100644 index 0000000..c40ef7a --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalAssignRequest.java @@ -0,0 +1,33 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import com.cmobile.unifiedtms.entity.restmodel.result.data.TerminalSimple; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +public class TerminalAssignRequest implements Serializable { + + private UUID groupId; + private String sn; + + public TerminalAssignRequest() { + } + + public UUID getGroupId() { + return groupId; + } + + public void setGroupId(UUID groupId) { + this.groupId = groupId; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalDetailRequest.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalDetailRequest.java new file mode 100644 index 0000000..358f7ee --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/request/TerminalDetailRequest.java @@ -0,0 +1,20 @@ +package com.cmobile.unifiedtms.entity.restmodel.request; + +import java.io.Serializable; +import java.util.UUID; + +public class TerminalDetailRequest implements Serializable { + + private String sn; + + public TerminalDetailRequest() { + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailExtResult.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailExtResult.java new file mode 100644 index 0000000..4cbf6ad --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailExtResult.java @@ -0,0 +1,43 @@ +package com.cmobile.unifiedtms.entity.restmodel.result; + +import java.util.Date; + +public class BaseDetailExtResult extends BaseResult { + + private T data; + private T2 dataExt; + private Date initTime; + + public BaseDetailExtResult() { + } + + /** + * @return the data + */ + public T getData() { + return data; + } + + /** + * @param data the data to set + */ + public void setData(T data) { + this.data = data; + } + + public T2 getDataExt() { + return dataExt; + } + + public void setDataExt(T2 dataExt) { + this.dataExt = dataExt; + } + + public Date getInitTime() { + return initTime; + } + + public void setInitTime(Date initTime) { + this.initTime = initTime; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailResult.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailResult.java new file mode 100644 index 0000000..fc4e254 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseDetailResult.java @@ -0,0 +1,24 @@ +package com.cmobile.unifiedtms.entity.restmodel.result; + +public class BaseDetailResult extends BaseResult { + + private T data; + + public BaseDetailResult() { + } + + /** + * @return the data + */ + public T getData() { + return data; + } + + /** + * @param data the data to set + */ + public void setData(T data) { + this.data = data; + } + +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseIdResult.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseIdResult.java new file mode 100644 index 0000000..df2bfa0 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseIdResult.java @@ -0,0 +1,24 @@ +package com.cmobile.unifiedtms.entity.restmodel.result; + +public class BaseIdResult extends BaseResult { + + private T id; + + public BaseIdResult() { + } + + /** + * @return the data + */ + public T getId() { + return id; + } + + /** + * @param id the data to set + */ + public void setId(T id) { + this.id = id; + } + +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListExtResult.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListExtResult.java new file mode 100644 index 0000000..b0f7eec --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListExtResult.java @@ -0,0 +1,56 @@ +package com.cmobile.unifiedtms.entity.restmodel.result; + +import java.util.Collections; +import java.util.Date; +import java.util.List; + +public class BaseListExtResult extends BaseResult { + + private List rows; + private T2 data; + private Date initTime; + + public BaseListExtResult() { + } + + /** + * @return the rows + */ + public List getRows() { + if(rows == null) { + rows = Collections.EMPTY_LIST; + } + return rows; + } + + /** + * @param rows the rows to set + */ + public void setRows(List rows) { + this.rows = rows; + } + + /** + * @return the data + */ + public T2 getData() { + return data; + } + + /** + * @param data the data to set + */ + public void setData(T2 data) { + this.data = data; + } + + public Date getInitTime() { + return initTime; + } + + public void setInitTime(Date initTime) { + this.initTime = initTime; + } + +} + diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListResult.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListResult.java new file mode 100644 index 0000000..bd6d252 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseListResult.java @@ -0,0 +1,31 @@ +package com.cmobile.unifiedtms.entity.restmodel.result; + +import java.util.Collections; +import java.util.List; + +public class BaseListResult extends BaseResult { + + private List rows; + + public BaseListResult() { + } + + /** + * @return the rows + */ + public List getRows() { + if(rows == null) { + rows = Collections.EMPTY_LIST; + } + return rows; + } + + /** + * @param rows the rows to set + */ + public void setRows(List rows) { + this.rows = rows; + } + +} + diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BasePaginatedResult.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BasePaginatedResult.java new file mode 100644 index 0000000..079767c --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BasePaginatedResult.java @@ -0,0 +1,76 @@ +package com.cmobile.unifiedtms.entity.restmodel.result; + +import java.util.Collections; +import java.util.List; + +public class BasePaginatedResult extends BaseResult { + + private int pageSize; + private int totalPage; + private int total; + private List rows; + + public BasePaginatedResult() { + } + + /** + * @return the pageSize + */ + public int getPageSize() { + return pageSize; + } + + /** + * @param pageSize the pageSize to set + */ + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + /** + * @return the totalPage + */ + public int getTotalPage() { + return totalPage; + } + + /** + * @param totalPage the totalPage to set + */ + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + /** + * @return the total + */ + public int getTotal() { + return total; + } + + /** + * @param total the total to set + */ + public void setTotal(int total) { + this.total = total; + } + + /** + * @return the rows + */ + public List getRows() { + if(rows == null) { + rows = Collections.EMPTY_LIST; + } + return rows; + } + + /** + * @param rows the rows to set + */ + public void setRows(List rows) { + this.rows = rows; + } + +} + diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseResult.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseResult.java new file mode 100644 index 0000000..f84a786 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/BaseResult.java @@ -0,0 +1,38 @@ +package com.cmobile.unifiedtms.entity.restmodel.result; + +import java.io.Serializable; + +public class BaseResult implements Serializable { + + private String responseCode; + private String responseDesc; + + /** + * @return the responseCode + */ + public String getResponseCode() { + return responseCode; + } + + /** + * @param responseCode the responseCode to set + */ + public void setResponseCode(String responseCode) { + this.responseCode = responseCode; + } + + /** + * @return the responseDesc + */ + public String getResponseDesc() { + return responseDesc; + } + + /** + * @param responseDesc the responseDesc to set + */ + public void setResponseDesc(String responseDesc) { + this.responseDesc = responseDesc; + } + +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/AppSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/AppSimple.java new file mode 100644 index 0000000..17ec896 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/AppSimple.java @@ -0,0 +1,35 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Date; + +public class AppSimple implements Serializable { + + private String appName; + private String packageName; + private String appVersion; + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getAppVersion() { + return appVersion; + } + + public void setAppVersion(String appVersion) { + this.appVersion = appVersion; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/CheckParameterUpdateExt.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/CheckParameterUpdateExt.java new file mode 100644 index 0000000..1444946 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/CheckParameterUpdateExt.java @@ -0,0 +1,79 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; + +public class CheckParameterUpdateExt implements Serializable { + + private boolean updateTerminal; + private boolean updateAcquirer; + private boolean updateCard; + private boolean updateAid; + private boolean updateCtlsAid; + private boolean updateCapk; + private boolean updateResponseCode; + private boolean keepBatch; + + public boolean isUpdateTerminal() { + return updateTerminal; + } + + public void setUpdateTerminal(boolean updateTerminal) { + this.updateTerminal = updateTerminal; + } + + public boolean isUpdateAcquirer() { + return updateAcquirer; + } + + public void setUpdateAcquirer(boolean updateAcquirer) { + this.updateAcquirer = updateAcquirer; + } + + public boolean isUpdateCard() { + return updateCard; + } + + public void setUpdateCard(boolean updateCard) { + this.updateCard = updateCard; + } + + public boolean isUpdateAid() { + return updateAid; + } + + public void setUpdateAid(boolean updateAid) { + this.updateAid = updateAid; + } + + public boolean isUpdateCtlsAid() { + return updateCtlsAid; + } + + public void setUpdateCtlsAid(boolean updateCtlsAid) { + this.updateCtlsAid = updateCtlsAid; + } + + public boolean isUpdateCapk() { + return updateCapk; + } + + public void setUpdateCapk(boolean updateCapk) { + this.updateCapk = updateCapk; + } + + public boolean isUpdateResponseCode() { + return updateResponseCode; + } + + public void setUpdateResponseCode(boolean updateResponseCode) { + this.updateResponseCode = updateResponseCode; + } + + public boolean isKeepBatch() { + return keepBatch; + } + + public void setKeepBatch(boolean keepBatch) { + this.keepBatch = keepBatch; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelDetail.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelDetail.java new file mode 100644 index 0000000..a728da2 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelDetail.java @@ -0,0 +1,69 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +public class DeviceModelDetail implements Serializable { + + private UUID id; + private String model; + private String modelInformation; + private String vendorName; + private String vendorCountry; + + public DeviceModelDetail() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getModelInformation() { + return modelInformation; + } + + public void setModelInformation(String modelInformation) { + this.modelInformation = modelInformation; + } + + public String getVendorName() { + return vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } + + public String getVendorCountry() { + return vendorCountry; + } + + public void setVendorCountry(String vendorCountry) { + this.vendorCountry = vendorCountry; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeviceModelDetail that = (DeviceModelDetail) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelSimple.java new file mode 100644 index 0000000..57ed2ab --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceModelSimple.java @@ -0,0 +1,52 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +public class DeviceModelSimple implements Serializable { + + private UUID id; + private String model; + private String vendorName; + + public DeviceModelSimple() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getVendorName() { + return vendorName; + } + + public void setVendorName(String vendorName) { + this.vendorName = vendorName; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeviceModelSimple that = (DeviceModelSimple) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileDetail.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileDetail.java new file mode 100644 index 0000000..8d0b368 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileDetail.java @@ -0,0 +1,130 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import com.haulmont.chile.core.annotations.NumberFormat; + +import javax.persistence.Column; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; +import java.util.Objects; +import java.util.UUID; + +public class DeviceProfileDetail implements Serializable { + + private UUID id; + private String name; + private Integer heartbeatInterval; + private Integer diagnosticInterval; + private Boolean maskHomeButton = false; + private Boolean maskStatusBar = false; + private Boolean scheduleReboot = false; + private Date scheduleRebootTime; + private Boolean relocationAlert; + private Integer movingThreshold; + private Boolean isDefault; + + public DeviceProfileDetail() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getHeartbeatInterval() { + return heartbeatInterval; + } + + public void setHeartbeatInterval(Integer heartbeatInterval) { + this.heartbeatInterval = heartbeatInterval; + } + + public Integer getDiagnosticInterval() { + return diagnosticInterval; + } + + public void setDiagnosticInterval(Integer diagnosticInterval) { + this.diagnosticInterval = diagnosticInterval; + } + + public Boolean getMaskHomeButton() { + return maskHomeButton; + } + + public void setMaskHomeButton(Boolean maskHomeButton) { + this.maskHomeButton = maskHomeButton; + } + + public Boolean getMaskStatusBar() { + return maskStatusBar; + } + + public void setMaskStatusBar(Boolean maskStatusBar) { + this.maskStatusBar = maskStatusBar; + } + + public Boolean getScheduleReboot() { + return scheduleReboot; + } + + public void setScheduleReboot(Boolean scheduleReboot) { + this.scheduleReboot = scheduleReboot; + } + + public Date getScheduleRebootTime() { + return scheduleRebootTime; + } + + public void setScheduleRebootTime(Date scheduleRebootTime) { + this.scheduleRebootTime = scheduleRebootTime; + } + + public Boolean getRelocationAlert() { + return relocationAlert; + } + + public void setRelocationAlert(Boolean relocationAlert) { + this.relocationAlert = relocationAlert; + } + + public Integer getMovingThreshold() { + return movingThreshold; + } + + public void setMovingThreshold(Integer movingThreshold) { + this.movingThreshold = movingThreshold; + } + + public Boolean getDefault() { + return isDefault; + } + + public void setDefault(Boolean aDefault) { + isDefault = aDefault; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeviceProfileDetail that = (DeviceProfileDetail) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileSimple.java new file mode 100644 index 0000000..dd282a4 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DeviceProfileSimple.java @@ -0,0 +1,58 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import com.haulmont.chile.core.annotations.NumberFormat; + +import javax.persistence.Column; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; +import java.util.Objects; +import java.util.UUID; + +public class DeviceProfileSimple implements Serializable { + + private UUID id; + private String name; + private Boolean isDefault; + + public DeviceProfileSimple() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getDefault() { + return isDefault; + } + + public void setDefault(Boolean aDefault) { + this.isDefault = aDefault; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeviceProfileSimple that = (DeviceProfileSimple) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DiagnosticSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DiagnosticSimple.java new file mode 100644 index 0000000..31b13de --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DiagnosticSimple.java @@ -0,0 +1,164 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import com.cmobile.unifiedtms.entity.ApplicationSimple; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +public class DiagnosticSimple extends HearbeatSimple { + + private String meid; + private Long totalMemory; + private Long availableMemory; + private Long totalFlashMemory; + private Long availableFlashMemory; + private Long totalMobileData; + private Integer switchingTimes; + private Integer currentBootTime; + private Integer totalBootTime; + private Double totalLengthPrinted; + private Integer swipingCardTimes; + private Integer dipInsertingTimes; + private Integer nfcCardReadingTimes; + private Integer frontCameraOpenTimes; + private Integer rearCameraOpenTimes; + private Integer chargeTimes; + private List installedApps; + + public String getMeid() { + return meid; + } + + public void setMeid(String meid) { + this.meid = meid; + } + + public Long getTotalMemory() { + return totalMemory; + } + + public void setTotalMemory(Long totalMemory) { + this.totalMemory = totalMemory; + } + + public Long getAvailableMemory() { + return availableMemory; + } + + public void setAvailableMemory(Long availableMemory) { + this.availableMemory = availableMemory; + } + + public Long getTotalFlashMemory() { + return totalFlashMemory; + } + + public void setTotalFlashMemory(Long totalFlashMemory) { + this.totalFlashMemory = totalFlashMemory; + } + + public Long getAvailableFlashMemory() { + return availableFlashMemory; + } + + public void setAvailableFlashMemory(Long availableFlashMemory) { + this.availableFlashMemory = availableFlashMemory; + } + + public Long getTotalMobileData() { + return totalMobileData; + } + + public void setTotalMobileData(Long totalMobileData) { + this.totalMobileData = totalMobileData; + } + + public Integer getSwitchingTimes() { + return switchingTimes; + } + + public void setSwitchingTimes(Integer switchingTimes) { + this.switchingTimes = switchingTimes; + } + + public Integer getCurrentBootTime() { + return currentBootTime; + } + + public void setCurrentBootTime(Integer currentBootTime) { + this.currentBootTime = currentBootTime; + } + + public Integer getTotalBootTime() { + return totalBootTime; + } + + public void setTotalBootTime(Integer totalBootTime) { + this.totalBootTime = totalBootTime; + } + + public Double getTotalLengthPrinted() { + return totalLengthPrinted; + } + + public void setTotalLengthPrinted(Double totalLengthPrinted) { + this.totalLengthPrinted = totalLengthPrinted; + } + + public Integer getSwipingCardTimes() { + return swipingCardTimes; + } + + public void setSwipingCardTimes(Integer swipingCardTimes) { + this.swipingCardTimes = swipingCardTimes; + } + + public Integer getDipInsertingTimes() { + return dipInsertingTimes; + } + + public void setDipInsertingTimes(Integer dipInsertingTimes) { + this.dipInsertingTimes = dipInsertingTimes; + } + + public Integer getNfcCardReadingTimes() { + return nfcCardReadingTimes; + } + + public void setNfcCardReadingTimes(Integer nfcCardReadingTimes) { + this.nfcCardReadingTimes = nfcCardReadingTimes; + } + + public Integer getFrontCameraOpenTimes() { + return frontCameraOpenTimes; + } + + public void setFrontCameraOpenTimes(Integer frontCameraOpenTimes) { + this.frontCameraOpenTimes = frontCameraOpenTimes; + } + + public Integer getRearCameraOpenTimes() { + return rearCameraOpenTimes; + } + + public void setRearCameraOpenTimes(Integer rearCameraOpenTimes) { + this.rearCameraOpenTimes = rearCameraOpenTimes; + } + + public Integer getChargeTimes() { + return chargeTimes; + } + + public void setChargeTimes(Integer chargeTimes) { + this.chargeTimes = chargeTimes; + } + + public List getInstalledApps() { + return installedApps; + } + + public void setInstalledApps(List installedApps) { + this.installedApps = installedApps; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskDetail.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskDetail.java new file mode 100644 index 0000000..4f6b4be --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskDetail.java @@ -0,0 +1,106 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class DownloadTaskDetail implements Serializable { + + private UUID id; + private String name; + private Integer downloadTimeType; + private String downloadTime; + private Integer installationTimeType; + private String installationTime; + private Integer installationNotification; + private List applicationIds; + private List terminalGroupIds; + private Integer status; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getDownloadTimeType() { + return downloadTimeType; + } + + public void setDownloadTimeType(Integer downloadTimeType) { + this.downloadTimeType = downloadTimeType; + } + + public String getDownloadTime() { + return downloadTime; + } + + public void setDownloadTime(String downloadTime) { + this.downloadTime = downloadTime; + } + + public Integer getInstallationTimeType() { + return installationTimeType; + } + + public void setInstallationTimeType(Integer installationTimeType) { + this.installationTimeType = installationTimeType; + } + + public String getInstallationTime() { + return installationTime; + } + + public void setInstallationTime(String installationTime) { + this.installationTime = installationTime; + } + + public Integer getInstallationNotification() { + return installationNotification; + } + + public void setInstallationNotification(Integer installationNotification) { + this.installationNotification = installationNotification; + } + + public List getApplicationIds() { + if(applicationIds == null) { + applicationIds = new ArrayList<>(); + } + return applicationIds; + } + + public void setApplicationIds(List applicationIds) { + this.applicationIds = applicationIds; + } + + public List getTerminalGroupIds() { + if(terminalGroupIds == null) { + terminalGroupIds = new ArrayList<>(); + } + return terminalGroupIds; + } + + public void setTerminalGroupIds(List terminalGroupIds) { + this.terminalGroupIds = terminalGroupIds; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskSimple.java new file mode 100644 index 0000000..c7cbd86 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/DownloadTaskSimple.java @@ -0,0 +1,37 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class DownloadTaskSimple implements Serializable { + + private UUID id; + private String name; + private Integer status; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/Feature.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/Feature.java new file mode 100644 index 0000000..bf4dea6 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/Feature.java @@ -0,0 +1,33 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; + +public class Feature implements Serializable { + + private String title; + private boolean value; + + public Feature() { + } + + public Feature(String title, boolean value) { + this.title = title; + this.value = value; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public boolean isValue() { + return value; + } + + public void setValue(boolean value) { + this.value = value; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/HearbeatSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/HearbeatSimple.java new file mode 100644 index 0000000..f161160 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/HearbeatSimple.java @@ -0,0 +1,119 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import com.cmobile.unifiedtms.entity.Terminal; +import com.haulmont.chile.core.annotations.NumberFormat; +import com.haulmont.cuba.core.entity.annotation.OnDeleteInverse; +import com.haulmont.cuba.core.global.DeletePolicy; + +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; +import java.util.Objects; +import java.util.UUID; + +public class HearbeatSimple implements Serializable { + + private String terminalSN; + private Double batteryTemp; + private Integer batteryPercentage; + private Double latitude; + private Double longitude; + private Date updateTime; + protected String cellName; + protected String cellType; + protected Integer cellStrength; + protected String wifiName; + protected Integer wifiStrength; + + public String getTerminalSN() { + return terminalSN; + } + + public void setTerminalSN(String terminalSN) { + this.terminalSN = terminalSN; + } + + public Double getBatteryTemp() { + return batteryTemp; + } + + public void setBatteryTemp(Double batteryTemp) { + this.batteryTemp = batteryTemp; + } + + public Integer getBatteryPercentage() { + return batteryPercentage; + } + + public void setBatteryPercentage(Integer batteryPercentage) { + this.batteryPercentage = batteryPercentage; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public String getCellName() { + return cellName; + } + + public void setCellName(String cellName) { + this.cellName = cellName; + } + + public String getCellType() { + return cellType; + } + + public void setCellType(String cellType) { + this.cellType = cellType; + } + + public Integer getCellStrength() { + return cellStrength; + } + + public void setCellStrength(Integer cellStrength) { + this.cellStrength = cellStrength; + } + + public String getWifiName() { + return wifiName; + } + + public void setWifiName(String wifiName) { + this.wifiName = wifiName; + } + + public Integer getWifiStrength() { + return wifiStrength; + } + + public void setWifiStrength(Integer wifiStrength) { + this.wifiStrength = wifiStrength; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/MerchantSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/MerchantSimple.java new file mode 100644 index 0000000..30f07c6 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/MerchantSimple.java @@ -0,0 +1,51 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +public class MerchantSimple implements Serializable { + + private UUID id; + private String name; + private String companyName; + + public MerchantSimple() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MerchantSimple that = (MerchantSimple) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/ResponseCodeSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/ResponseCodeSimple.java new file mode 100644 index 0000000..d9403ab --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/ResponseCodeSimple.java @@ -0,0 +1,60 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +public class ResponseCodeSimple implements Serializable { + + private UUID id; + private String type; + private String code; + private String desc; + + public ResponseCodeSimple() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResponseCodeSimple that = (ResponseCodeSimple) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalDetail.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalDetail.java new file mode 100644 index 0000000..c247878 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalDetail.java @@ -0,0 +1,78 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +public class TerminalDetail implements Serializable { + + private UUID id; + private String sn; + private String imei; + private DeviceModelSimple model; + private MerchantSimple merchant; + private DeviceProfileSimple profile; + + public TerminalDetail() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public DeviceModelSimple getModel() { + return model; + } + + public void setModel(DeviceModelSimple model) { + this.model = model; + } + + public MerchantSimple getMerchant() { + return merchant; + } + + public void setMerchant(MerchantSimple merchant) { + this.merchant = merchant; + } + + public DeviceProfileSimple getProfile() { + return profile; + } + + public void setProfile(DeviceProfileSimple profile) { + this.profile = profile; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TerminalDetail that = (TerminalDetail) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalExtAddressSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalExtAddressSimple.java new file mode 100644 index 0000000..c0a2935 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalExtAddressSimple.java @@ -0,0 +1,86 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +public class TerminalExtAddressSimple implements Serializable { + + private UUID id; + private String sn; + private String terminalId; + private String merchantId; + private String merchantName1; + private String merchantName2; + private String merchantName3; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getTerminalId() { + return terminalId; + } + + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + public String getMerchantId() { + return merchantId; + } + + public void setMerchantId(String merchantId) { + this.merchantId = merchantId; + } + + public String getMerchantName1() { + return merchantName1; + } + + public void setMerchantName1(String merchantName1) { + this.merchantName1 = merchantName1; + } + + public String getMerchantName2() { + return merchantName2; + } + + public void setMerchantName2(String merchantName2) { + this.merchantName2 = merchantName2; + } + + public String getMerchantName3() { + return merchantName3; + } + + public void setMerchantName3(String merchantName3) { + this.merchantName3 = merchantName3; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TerminalExtAddressSimple that = (TerminalExtAddressSimple) o; + return id.equals(that.id) && + sn.equals(that.sn); + } + + @Override + public int hashCode() { + return Objects.hash(id, sn); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalFeatures.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalFeatures.java new file mode 100644 index 0000000..22531b3 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalFeatures.java @@ -0,0 +1,105 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class TerminalFeatures implements Serializable { + + private UUID id; + private String sn; + private String imei; + private String terminalId; + private String appVersion; + private String provider; + private String pmPeriod; + private Double latitude; + private Double longitude; + private List featureTransactions; + + public TerminalFeatures() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public String getTerminalId() { + return terminalId; + } + + public void setTerminalId(String terminalId) { + this.terminalId = terminalId; + } + + public String getAppVersion() { + return appVersion; + } + + public void setAppVersion(String appVersion) { + this.appVersion = appVersion; + } + + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + + public String getPmPeriod() { + return pmPeriod; + } + + public void setPmPeriod(String pmPeriod) { + this.pmPeriod = pmPeriod; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public List getFeatureTransactions() { + if(featureTransactions == null) { + featureTransactions = new ArrayList<>(); + } + return featureTransactions; + } + + public void setFeatureTransactions(List featureTransactions) { + this.featureTransactions = featureTransactions; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalGroupSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalGroupSimple.java new file mode 100644 index 0000000..ba54d6e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalGroupSimple.java @@ -0,0 +1,62 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.*; + +public class TerminalGroupSimple implements Serializable { + + private UUID id; + private String name; + private String description; + private List terminals; + + public TerminalGroupSimple() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getTerminals() { + if(terminals == null) { + terminals = new ArrayList<>(); + } + return terminals; + } + + public void setTerminals(List terminals) { + this.terminals = terminals; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TerminalGroupSimple that = (TerminalGroupSimple) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalSimple.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalSimple.java new file mode 100644 index 0000000..f36abfc --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/TerminalSimple.java @@ -0,0 +1,78 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +public class TerminalSimple implements Serializable { + + private UUID id; + private String sn; + private String imei; + private String modelName; + private String merchantName; + private String profileName; + + public TerminalSimple() {} + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public String getModelName() { + return modelName; + } + + public void setModelName(String modelName) { + this.modelName = modelName; + } + + public String getMerchantName() { + return merchantName; + } + + public void setMerchantName(String merchantName) { + this.merchantName = merchantName; + } + + public String getProfileName() { + return profileName; + } + + public void setProfileName(String profileName) { + this.profileName = profileName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TerminalSimple that = (TerminalSimple) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateAidData.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateAidData.java new file mode 100644 index 0000000..6f2165b --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateAidData.java @@ -0,0 +1,16 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; + +public class UpdateAidData implements Serializable { + + private boolean updateAid; + + public boolean isUpdateAid() { + return updateAid; + } + + public void setUpdateAid(boolean updateAid) { + this.updateAid = updateAid; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCapkData.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCapkData.java new file mode 100644 index 0000000..cb43f6e --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCapkData.java @@ -0,0 +1,16 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; + +public class UpdateCapkData implements Serializable { + + private boolean updateCapk; + + public boolean isUpdateCapk() { + return updateCapk; + } + + public void setUpdateCapk(boolean updateCapk) { + this.updateCapk = updateCapk; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCardData.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCardData.java new file mode 100644 index 0000000..1209161 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateCardData.java @@ -0,0 +1,16 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; + +public class UpdateCardData implements Serializable { + + private boolean updateCard; + + public boolean isUpdateCard() { + return updateCard; + } + + public void setUpdateCard(boolean updateCard) { + this.updateCard = updateCard; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateContactlessAidData.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateContactlessAidData.java new file mode 100644 index 0000000..9109c3f --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateContactlessAidData.java @@ -0,0 +1,16 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; + +public class UpdateContactlessAidData implements Serializable { + + private boolean updateCtlsAid; + + public boolean isUpdateCtlsAid() { + return updateCtlsAid; + } + + public void setUpdateCtlsAid(boolean updateCtlsAid) { + this.updateCtlsAid = updateCtlsAid; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateTerminalData.java b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateTerminalData.java new file mode 100644 index 0000000..58a996c --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/entity/restmodel/result/data/UpdateTerminalData.java @@ -0,0 +1,71 @@ +package com.cmobile.unifiedtms.entity.restmodel.result.data; + +import java.io.Serializable; +import java.util.List; + +public class UpdateTerminalData implements Serializable { + + private boolean updateTerminal; + private boolean updateCard; + private boolean updateAid; + private boolean updateCtlsAid; + private boolean updateCapk; + private boolean keepBatch; + private List responseCodes; + + public boolean isUpdateTerminal() { + return updateTerminal; + } + + public void setUpdateTerminal(boolean updateTerminal) { + this.updateTerminal = updateTerminal; + } + + public boolean isUpdateCard() { + return updateCard; + } + + public void setUpdateCard(boolean updateCard) { + this.updateCard = updateCard; + } + + public boolean isUpdateAid() { + return updateAid; + } + + public void setUpdateAid(boolean updateAid) { + this.updateAid = updateAid; + } + + public boolean isUpdateCtlsAid() { + return updateCtlsAid; + } + + public void setUpdateCtlsAid(boolean updateCtlsAid) { + this.updateCtlsAid = updateCtlsAid; + } + + public boolean isUpdateCapk() { + return updateCapk; + } + + public void setUpdateCapk(boolean updateCapk) { + this.updateCapk = updateCapk; + } + + public boolean isKeepBatch() { + return keepBatch; + } + + public void setKeepBatch(boolean keepBatch) { + this.keepBatch = keepBatch; + } + + public void setResponseCodes(List responseCodes) { + this.responseCodes = responseCodes; + } + + public List getResponseCodes() { + return responseCodes; + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/exception/ImportFileEofEvaluationException.java b/modules/global/src/com/cmobile/unifiedtms/exception/ImportFileEofEvaluationException.java new file mode 100644 index 0000000..a6416c0 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/exception/ImportFileEofEvaluationException.java @@ -0,0 +1,25 @@ +package com.cmobile.unifiedtms.exception; + +/** + * Created by aleksey on 21/10/2016. + */ +public class ImportFileEofEvaluationException extends Exception { + public ImportFileEofEvaluationException() { + } + + public ImportFileEofEvaluationException(String message) { + super(message); + } + + public ImportFileEofEvaluationException(String message, Throwable cause) { + super(message, cause); + } + + public ImportFileEofEvaluationException(Throwable cause) { + super(cause); + } + + public ImportFileEofEvaluationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/modules/global/src/com/cmobile/unifiedtms/metadata.xml b/modules/global/src/com/cmobile/unifiedtms/metadata.xml new file mode 100644 index 0000000..3f467e7 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/metadata.xml @@ -0,0 +1,8 @@ + + + + + com.cmobile.unifiedtms.entity.TerminalGroupImport + + + \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/persistence.xml b/modules/global/src/com/cmobile/unifiedtms/persistence.xml new file mode 100644 index 0000000..6a1c160 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/persistence.xml @@ -0,0 +1,38 @@ + + + + com.cmobile.unifiedtms.entity.Country + com.cmobile.unifiedtms.entity.States + com.cmobile.unifiedtms.entity.City + com.cmobile.unifiedtms.entity.MerchantType + com.cmobile.unifiedtms.entity.Terminal + com.cmobile.unifiedtms.entity.Merchant + com.cmobile.unifiedtms.entity.District + com.cmobile.unifiedtms.entity.DeviceModel + com.cmobile.unifiedtms.entity.TerminalGroup + com.cmobile.unifiedtms.entity.Application + com.cmobile.unifiedtms.entity.ContactPerson + com.cmobile.unifiedtms.entity.DeviceProfile + com.cmobile.unifiedtms.entity.HeartBeat + com.cmobile.unifiedtms.entity.DiagnosticInfo + com.cmobile.unifiedtms.entity.DownloadTask + com.cmobile.unifiedtms.entity.DownloadTaskLog + com.cmobile.unifiedtms.entity.TerminalLastHeartBeat + com.cmobile.unifiedtms.entity.TerminalLastDiagnosticInfo + com.cmobile.unifiedtms.entity.ApplicationSimple + com.cmobile.unifiedtms.entity.DeleteTask + com.cmobile.unifiedtms.entity.DeleteTaskLog + com.cmobile.unifiedtms.entity.TerminalLink + com.cmobile.unifiedtms.entity.TerminalReport + com.cmobile.unifiedtms.entity.TerminalLastUpdate + com.cmobile.unifiedtms.entity.TerminalLastStepUpdate + com.cmobile.unifiedtms.entity.TerminalAckUpdate + com.cmobile.unifiedtms.entity.ResponseCode + com.cmobile.unifiedtms.entity.DeviceProfileApp + com.cmobile.unifiedtms.entity.TerminalHeartBeat + com.cmobile.unifiedtms.entity.HeartbeatSummary + com.cmobile.unifiedtms.entity.VHeartBeat + com.cmobile.unifiedtms.entity.TerminalProfiling + com.cmobile.unifiedtms.entity.TerminalProfilingItem + + diff --git a/modules/global/src/com/cmobile/unifiedtms/security/UserSessionExistsException.java b/modules/global/src/com/cmobile/unifiedtms/security/UserSessionExistsException.java new file mode 100644 index 0000000..d6de53d --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/security/UserSessionExistsException.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018 login-restrictions + * https://github.com/cuba-platform/sample-login-restrictions/blob/3b8009380fc04d04b0b49428d471d1f1d7107da7/modules/global/src/com/company/loginrestrictions/security/UserSessionExistsException.java + */ + +package com.cmobile.unifiedtms.security; + +import com.haulmont.cuba.core.global.Logging; +import com.haulmont.cuba.core.global.SupportedByClient; +import com.haulmont.cuba.security.global.LoginException; + +@SupportedByClient +@Logging(Logging.Type.BRIEF) +public class UserSessionExistsException extends LoginException { + protected String login; + + public UserSessionExistsException(String login) { + super("User session exists"); + this.login = login; + } +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/APIService.java b/modules/global/src/com/cmobile/unifiedtms/service/APIService.java new file mode 100644 index 0000000..763e527 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/APIService.java @@ -0,0 +1,86 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.DeviceProfile; +import com.cmobile.unifiedtms.entity.Terminal; +import com.cmobile.unifiedtms.entity.restmodel.request.*; +import com.cmobile.unifiedtms.entity.restmodel.result.*; +import com.cmobile.unifiedtms.entity.restmodel.result.data.*; +import com.cmobile.unifiedtms.ext.entity.Acquirer; +import com.cmobile.unifiedtms.ext.entity.Aid; +import com.cmobile.unifiedtms.ext.entity.Card; +import com.cmobile.unifiedtms.ext.entity.TerminalExt; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public interface APIService { + String NAME = "tms_APIService"; + + /** Merchant **/ + public BasePaginatedResult listMerchant(PaginatedRequest req); + /** End of Merchant **/ + /** Device Model **/ + public BasePaginatedResult listModel(PaginatedRequest req); + public BaseDetailResult getModel(DetailRequest req); + /** End of Device Model **/ + /** Device Profile **/ + public BasePaginatedResult listProfile(PaginatedRequest req); + public BaseDetailResult getProfile(DetailRequest req); + /** End of Device Profile **/ + /** Terminal **/ + public BaseIdResult addTerminal(AddTerminalRequest req); + public BasePaginatedResult listTerminal(PaginatedRequest req); + public BaseDetailResult getTerminal(TerminalDetailRequest req); + /** End of Terminal **/ + /** Terminal Ext **/ + public BaseDetailResult getTerminalExtAddress(TerminalDetailRequest req); + /** End of Terminal Ext **/ + /** Diagnostic & Heartbeat **/ + public BaseDetailResult lastHeartbeat(String sn); + public BaseDetailResult lastDiagnostic(String sn); + public BaseListResult listHeartbeat(String sn, Date startDate, Date endDate); + /** End of Diagnostic & Heartbeat **/ + /** Terminal Group **/ + public BasePaginatedResult listTerminalGroup(PaginatedRequest req); + public BaseIdResult addTerminalGroup(AddTerminalGroupRequest req); + public BaseResult editTerminalGroup(EditTerminalGroupRequest req); + public BaseResult deleteTerminalGroup(DeleteRequest req); + public BaseResult addTerminalToGroup(TerminalAssignRequest req); + public BaseResult removeTerminalFromGroup(TerminalAssignRequest req); + /** End of Terminal Group **/ + /** Application **/ + public BaseIdResult addApplication(AddApplicationRequest req); + /** End of Application **/ + /** Download Task **/ + public BaseIdResult addDownloadTask(AddDownloadTaskRequest req); + public BasePaginatedResult listDownloadTask(PaginatedRequest req); + public BaseDetailResult getDownloadTask(DetailRequest req); + /** End of Download Task **/ + + /** INIT Profile **/ + public Map init(InitProfileRequest req); + public BaseListExtResult initAidList(InitProfileRequest req); + public BaseListExtResult initCtlsAidList(InitProfileRequest req); + public BaseListExtResult initCapkList(InitProfileRequest req); + public BaseListExtResult initCardList(InitProfileRequest req); + public BaseDetailExtResult initTerminal(InitProfileRequest req); + public BaseDetailExtResult checkParameterUpdate(CheckUpdateRequest req); + public BaseResult ackParameterUpdate(AckParameterRequest req); + /** End of INIT Profile **/ + + public void updateTerminalUpdateCaches(); + public void cleanupTerminalUpdateCaches(); + + public void onTerminalUpdateProfile(Terminal terminal); + public void onProfileUpdate(DeviceProfile profile); + + /** update apis */ + public BaseDetailResult checkParameterUpdateExt(CheckUpdateRequest req); + public BaseListResult initResponseCode(InitProfileRequest req); + public BaseDetailResult initTerminalExt(InitProfileRequest req); + public BaseListResult initAcquirer(InitProfileRequest req); + /** end of update apis */ + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/ApkService.java b/modules/global/src/com/cmobile/unifiedtms/service/ApkService.java new file mode 100644 index 0000000..09f1de2 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/ApkService.java @@ -0,0 +1,9 @@ +package com.cmobile.unifiedtms.service; + +import com.pras.Manifest; + +public interface ApkService { + String NAME = "tms_ApkService"; + + public Manifest extractManifest(byte[] bytes) throws Exception; +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/ChartDataService.java b/modules/global/src/com/cmobile/unifiedtms/service/ChartDataService.java new file mode 100644 index 0000000..6259e53 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/ChartDataService.java @@ -0,0 +1,12 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.chartdata.PieChartData; + +import java.util.List; + +public interface ChartDataService { + String NAME = "tms_ChartDataService"; + + public List getDownloadStats(); + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/DeleteTaskService.java b/modules/global/src/com/cmobile/unifiedtms/service/DeleteTaskService.java new file mode 100644 index 0000000..16e6990 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/DeleteTaskService.java @@ -0,0 +1,10 @@ +package com.cmobile.unifiedtms.service; + +public interface DeleteTaskService { + String NAME = "tms_DeleteTaskService"; + + public void startDeleteTasks() throws Exception; + public void broadcastTasksToDevices() throws Exception; + public String updateTaskStatuses() throws Exception; + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/DeviceInitService.java b/modules/global/src/com/cmobile/unifiedtms/service/DeviceInitService.java new file mode 100644 index 0000000..18f5ed4 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/DeviceInitService.java @@ -0,0 +1,12 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.DeviceProfile; +import com.cmobile.unifiedtms.entity.Terminal; + +public interface DeviceInitService { + String NAME = "tms_DeviceInitService"; + + public void publishInit(DeviceProfile profile, Terminal terminal); + public void publishInitToProfile(DeviceProfile profile); + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/DownloadTaskService.java b/modules/global/src/com/cmobile/unifiedtms/service/DownloadTaskService.java new file mode 100644 index 0000000..4cb42b2 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/DownloadTaskService.java @@ -0,0 +1,11 @@ +package com.cmobile.unifiedtms.service; + +public interface DownloadTaskService { + String NAME = "tms_DownloadTaskService"; + + public void startDownloadTasks() throws Exception; + public void broadcastTasksToDevices() throws Exception; + public String updateTaskStatuses() throws Exception; + public void broadcastChangeProfileTaskToDevices() throws Exception; + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/EchoService.java b/modules/global/src/com/cmobile/unifiedtms/service/EchoService.java new file mode 100644 index 0000000..eee02bc --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/EchoService.java @@ -0,0 +1,7 @@ +package com.cmobile.unifiedtms.service; + +public interface EchoService { + String NAME = "tms_EchoService"; + + public void sendEcho() throws Exception; +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/FileService.java b/modules/global/src/com/cmobile/unifiedtms/service/FileService.java new file mode 100644 index 0000000..f456481 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/FileService.java @@ -0,0 +1,18 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.misc.FileDownloadWrapper; +import com.haulmont.cuba.core.entity.FileDescriptor; +import org.springframework.web.bind.annotation.PathVariable; + +import javax.servlet.http.HttpServletResponse; + +public interface FileService { + String NAME = "tms_FileService"; + + void downloadFile(@PathVariable String fileDescriptorId, + HttpServletResponse response); + + FileDownloadWrapper uploadFileToRemote(FileDescriptor fd); + + FileDownloadWrapper uploadFileToRemote(FileDescriptor fd, boolean useFilename); +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/HeartBeatService.java b/modules/global/src/com/cmobile/unifiedtms/service/HeartBeatService.java new file mode 100644 index 0000000..045d253 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/HeartBeatService.java @@ -0,0 +1,10 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.restmodel.HeartBeatRequest; + +public interface HeartBeatService { + String NAME = "tms_HeartBeatService"; + + public boolean heartBeat(HeartBeatRequest heartBeatRequest); + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/LicenseService.java b/modules/global/src/com/cmobile/unifiedtms/service/LicenseService.java new file mode 100644 index 0000000..80be162 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/LicenseService.java @@ -0,0 +1,15 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.LicenseModel; +import com.license4j.ValidationStatus; +import com.haulmont.cuba.core.entity.FileDescriptor; + +public interface LicenseService { + String NAME = "tms_LicenseService"; + + public LicenseModel validateLicense() throws Exception; + public LicenseModel validateLicense(String licenseString) throws Exception; + public ValidationStatus installLicense(String licenseString) throws Exception; + public String getLicenseStringFromFile(FileDescriptor fileDescriptor) throws Exception; + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/NumericInfoWidgetService.java b/modules/global/src/com/cmobile/unifiedtms/service/NumericInfoWidgetService.java new file mode 100644 index 0000000..1c284b7 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/NumericInfoWidgetService.java @@ -0,0 +1,7 @@ +package com.cmobile.unifiedtms.service; + +public interface NumericInfoWidgetService { + String NAME = "tms_NumericInfoWidgetService"; + + public Number getNumberFromQueryTemplate(String queryTemplate); +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/ReportService.java b/modules/global/src/com/cmobile/unifiedtms/service/ReportService.java new file mode 100644 index 0000000..60e8029 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/ReportService.java @@ -0,0 +1,18 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.ExportReportBean; +import com.cmobile.unifiedtms.entity.enums.ExportType; +import com.cmobile.unifiedtms.entity.enums.ReportType; +import com.cmobile.unifiedtms.entity.misc.FileDownloadWrapper; +import com.cmobile.unifiedtms.entity.restmodel.result.BaseDetailResult; + +import java.util.Date; + +public interface ReportService { + String NAME = "tms_ReportService"; + + ExportReportBean exportReport(ReportType reportType, ExportType exportType) throws Exception; + ExportReportBean exportReportMidLocationReport() throws Exception; + BaseDetailResult exportDiagnosticReport(String vendorName, Date date) throws Exception; + BaseDetailResult exportLastHeartBeatReport(String vendorName, Date date) throws Exception; +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/ResponseCodeService.java b/modules/global/src/com/cmobile/unifiedtms/service/ResponseCodeService.java new file mode 100644 index 0000000..ea04b84 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/ResponseCodeService.java @@ -0,0 +1,13 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.ResponseCode; +import com.haulmont.cuba.core.entity.FileDescriptor; + +import java.util.List; + +public interface ResponseCodeService { + String NAME = "tms_ResponseCodeService"; + + public List parseResponseCodeFromFile(FileDescriptor fd) throws Exception; + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/TerminalExtService.java b/modules/global/src/com/cmobile/unifiedtms/service/TerminalExtService.java new file mode 100644 index 0000000..bcf6908 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/TerminalExtService.java @@ -0,0 +1,8 @@ +package com.cmobile.unifiedtms.service; + +public interface TerminalExtService { + String NAME = "tms_ExtTerminalService"; + + public String updateTerminalStatus(); + public String removeTerminalByTid(String terminalId); +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/TerminalGroupImporterService.java b/modules/global/src/com/cmobile/unifiedtms/service/TerminalGroupImporterService.java new file mode 100644 index 0000000..5067399 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/TerminalGroupImporterService.java @@ -0,0 +1,14 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.misc.TerminalGroupImportObjectWrapper; +import com.haulmont.cuba.core.entity.FileDescriptor; + +import java.util.List; + +public interface TerminalGroupImporterService { + String NAME = "tms_TerminalGroupImporterService"; + + List parseTerminalsFromFile(FileDescriptor fd) throws Exception; + + List parseTerminalsFromFileOptimized(FileDescriptor fd) throws Exception; +} diff --git a/modules/global/src/com/cmobile/unifiedtms/service/TerminalImporterService.java b/modules/global/src/com/cmobile/unifiedtms/service/TerminalImporterService.java new file mode 100644 index 0000000..00faf0f --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/TerminalImporterService.java @@ -0,0 +1,25 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.TerminalImportBean; +import com.cmobile.unifiedtms.entity.TerminalLink; +import com.cmobile.unifiedtms.entity.TerminalProfilingItem; +import com.cmobile.unifiedtms.entity.misc.TerminalImporterObjectWrapper; +import com.cmobile.unifiedtms.ext.entity.TerminalExt; +import com.haulmont.cuba.core.entity.FileDescriptor; + +import java.util.List; + +public interface TerminalImporterService { + String NAME = "tms_TerminalImporterService"; + + TerminalImporterObjectWrapper parseTerminalsFromFile(FileDescriptor fd) throws Exception; + boolean saveTerminal(TerminalLink terminalLink) throws Exception; + List parseTerminalsFromFile2(FileDescriptor fd) throws Exception; + String[] saveTerminal(TerminalImportBean terminal) throws Exception; + + List parseTerminalsFromEditFile(FileDescriptor fd) throws Exception; + boolean updateTerminal(TerminalExt terminal) throws Exception; + + List parseProfilingItems(FileDescriptor fd) throws Exception; + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/service/TerminalService.java b/modules/global/src/com/cmobile/unifiedtms/service/TerminalService.java new file mode 100644 index 0000000..cee5353 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/service/TerminalService.java @@ -0,0 +1,10 @@ +package com.cmobile.unifiedtms.service; + +import com.cmobile.unifiedtms.entity.restmodel.result.data.TerminalFeatures; + +public interface TerminalService { + String NAME = "tms_TerminalService"; + + public TerminalFeatures getTerminalByTid(String tid); + +} \ No newline at end of file diff --git a/modules/global/src/com/cmobile/unifiedtms/views.xml b/modules/global/src/com/cmobile/unifiedtms/views.xml new file mode 100644 index 0000000..b20f3f0 --- /dev/null +++ b/modules/global/src/com/cmobile/unifiedtms/views.xml @@ -0,0 +1,791 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/test/com/cmobile/unifiedtms/TmsTestContainer.java b/modules/test/com/cmobile/unifiedtms/TmsTestContainer.java new file mode 100644 index 0000000..00ca5ab --- /dev/null +++ b/modules/test/com/cmobile/unifiedtms/TmsTestContainer.java @@ -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 + } + + } +} \ No newline at end of file diff --git a/modules/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java b/modules/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java new file mode 100644 index 0000000..40187d8 --- /dev/null +++ b/modules/test/com/cmobile/unifiedtms/core/SampleIntegrationTest.java @@ -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 query = em.createQuery( + "select u from sec$User u where u.login = :userLogin", User.class); + query.setParameter("userLogin", "admin"); + List users = query.getResultList(); + tx.commit(); + Assertions.assertEquals(1, users.size()); + } + } +} \ No newline at end of file diff --git a/modules/test/com/cmobile/unifiedtms/test-app.properties b/modules/test/com/cmobile/unifiedtms/test-app.properties new file mode 100644 index 0000000..9d368fa --- /dev/null +++ b/modules/test/com/cmobile/unifiedtms/test-app.properties @@ -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 \ No newline at end of file diff --git a/modules/test/com/cmobile/unifiedtms/test-spring.xml b/modules/test/com/cmobile/unifiedtms/test-spring.xml new file mode 100644 index 0000000..dec5d53 --- /dev/null +++ b/modules/test/com/cmobile/unifiedtms/test-spring.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/modules/web/private/cache/retriever/catalog.xml b/modules/web/private/cache/retriever/catalog.xml new file mode 100644 index 0000000..e69de29 diff --git a/modules/web/src/com/cmobile/unifiedtms/rest-dispatcher-spring.xml b/modules/web/src/com/cmobile/unifiedtms/rest-dispatcher-spring.xml new file mode 100644 index 0000000..d5edee0 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/rest-dispatcher-spring.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/modules/web/src/com/cmobile/unifiedtms/rest-json-transformations.xml b/modules/web/src/com/cmobile/unifiedtms/rest-json-transformations.xml new file mode 100644 index 0000000..8da3dbc --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/rest-json-transformations.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/modules/web/src/com/cmobile/unifiedtms/rest-queries.xml b/modules/web/src/com/cmobile/unifiedtms/rest-queries.xml new file mode 100644 index 0000000..e6f59d0 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/rest-queries.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/modules/web/src/com/cmobile/unifiedtms/rest-services.xml b/modules/web/src/com/cmobile/unifiedtms/rest-services.xml new file mode 100644 index 0000000..e264611 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/rest-services.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/web/src/com/cmobile/unifiedtms/web-app.properties b/modules/web/src/com/cmobile/unifiedtms/web-app.properties new file mode 100644 index 0000000..f6dbe94 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web-app.properties @@ -0,0 +1,68 @@ +############################################################################### +# Configuration # +############################################################################### + +cuba.springContextConfig = +com/cmobile/unifiedtms/web-spring.xml + +cuba.dispatcherSpringContextConfig = +com/cmobile/unifiedtms/web-dispatcher-spring.xml + +cuba.persistenceConfig = +com/cmobile/unifiedtms/persistence.xml + +cuba.metadataConfig = +com/cmobile/unifiedtms/metadata.xml + +cuba.viewsConfig = +com/cmobile/unifiedtms/views.xml + +cuba.windowConfig = +com/cmobile/unifiedtms/web-screens.xml + +cuba.menuConfig = com/cmobile/unifiedtms/web-menu.xml + +cuba.permissionConfig = +com/cmobile/unifiedtms/web-permissions.xml + +cuba.mainMessagePack = +com.cmobile.unifiedtms.web + +cuba.anonymousSessionId = 3aa2d4b1-205c-de8c-bcb6-f4153ae617c7 + +cuba.creditsConfig = + + +############################################################################### +# Other # +############################################################################### + +# Middleware connection +cuba.connectionUrlList = http://localhost:8080/tms-core + +cuba.rest.anonymousEnabled = true + +# Set to false if the middleware works on different JVM +cuba.useLocalServiceInvocation = true + +cuba.webContextName = tms +cuba.availableLocales = English|en;Indonesian (Indonesia)|id_ID +cuba.localeSelectVisible = false +cuba.web.theme = helium +cuba.web.loginDialogPoweredByLinkVisible = false + +# Multi Tenancy +cubasdbmt.loginByTenantParamEnabled = true +cubasdbmt.tenantIdUrlParamName = tenantId +cuba.web.loginScreenId=login +cuba.web.mainScreenId=extMainScreen + +# Charts - Map +charts.map.apiKey = AIzaSyDP2Qptoyatz47wxDX2kjiIy1HiBgqMdiE +charts.map.defaultZoom = 13.0 +charts.map.defaultLatitude = -6.200000 +charts.map.defaultLongitude = 106.816666 + +# Rest Services +cuba.rest.servicesConfig=+com/cmobile/unifiedtms/rest-services.xml +cuba.rest.queriesConfig=+com/cmobile/unifiedtms/rest-queries.xml +cuba.rest.jsonTransformationConfig = +com/cmobile/unifiedtms/rest-json-transformations.xml +cuba.rest.client.id=clientid +cuba.rest.client.secret={noop}clientsecret +cuba.rest.client.tokenExpirationTimeSec=43200 +cuba.rest.client.refreshTokenExpirationTimeSpec=31536000 + +#cuba.legacyPasswordEncryptionModule = cuba_Md5EncryptionModule +#cuba.passwordEncryptionModule = cuba_Md5EncryptionModule +cuba.web.productionMode = false \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web-dispatcher-spring.xml b/modules/web/src/com/cmobile/unifiedtms/web-dispatcher-spring.xml new file mode 100644 index 0000000..fc23408 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web-dispatcher-spring.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web-menu.xml b/modules/web/src/com/cmobile/unifiedtms/web-menu.xml new file mode 100644 index 0000000..99582c3 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web-menu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web-permissions.xml b/modules/web/src/com/cmobile/unifiedtms/web-permissions.xml new file mode 100644 index 0000000..0c52ab0 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web-permissions.xml @@ -0,0 +1,3 @@ + + + diff --git a/modules/web/src/com/cmobile/unifiedtms/web-screens.xml b/modules/web/src/com/cmobile/unifiedtms/web-screens.xml new file mode 100644 index 0000000..9ea1b6e --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web-screens.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web-spring.xml b/modules/web/src/com/cmobile/unifiedtms/web-spring.xml new file mode 100644 index 0000000..7bf9815 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web-spring.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web/filter/BlockHttpMethodFilter.java b/modules/web/src/com/cmobile/unifiedtms/web/filter/BlockHttpMethodFilter.java new file mode 100644 index 0000000..bce1784 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/filter/BlockHttpMethodFilter.java @@ -0,0 +1,45 @@ +package com.cmobile.unifiedtms.web.filter; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class BlockHttpMethodFilter implements Filter { + + private String validHostHeaders; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // no-op + this.validHostHeaders = filterConfig.getInitParameter("validHostHeaders"); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + if(!httpRequest.getMethod().equalsIgnoreCase("POST") && + !httpRequest.getMethod().equalsIgnoreCase("GET")) { + httpResponse.sendError(405); + } else { + // validate 'Host' header + String hostHeader = httpRequest.getHeader("Host"); + String[] validHostHeaderArr = (this.validHostHeaders != null ? this.validHostHeaders.split(";") : new String[] {}); + boolean valid = false; + for(String validHost : validHostHeaderArr) { + valid |= hostHeader.equalsIgnoreCase(validHost); + } + if(!valid) { + httpResponse.sendError(403); + } else { + chain.doFilter(request, response); + } + } + } + + @Override + public void destroy() { + // no-op + } +} diff --git a/modules/web/src/com/cmobile/unifiedtms/web/filter/VaadinBlockDirListingFilter.java b/modules/web/src/com/cmobile/unifiedtms/web/filter/VaadinBlockDirListingFilter.java new file mode 100644 index 0000000..42be8e0 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/filter/VaadinBlockDirListingFilter.java @@ -0,0 +1,52 @@ +package com.cmobile.unifiedtms.web.filter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class VaadinBlockDirListingFilter implements Filter { + + private Logger logger = LoggerFactory.getLogger(VaadinBlockDirListingFilter.class.getName()); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // no-op + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + if(!httpRequest.getMethod().equalsIgnoreCase("POST") && + !httpRequest.getMethod().equalsIgnoreCase("GET")) { + httpResponse.sendError(405); + } else { + String pathInfo = httpRequest.getPathInfo(); + if(pathInfo != null && pathInfo.matches("\\/VAADIN(\\/)?.*")) { + // vaadin path + // check if has extension + if(pathInfo.matches("^(.*)\\.[a-z]+$")) { + // has extension + logger.info("VAADIN Dir but with extension: '{}'", pathInfo); + chain.doFilter(request, response); + } else { + // folder + logger.info("Send 403"); + httpResponse.sendError(403); + } + } else { + //logger.info("Not VAADIN Path: '{}'", pathInfo); + chain.doFilter(request, response); + } + } + } + + @Override + public void destroy() { + // no-op + } +} diff --git a/modules/web/src/com/cmobile/unifiedtms/web/messages.properties b/modules/web/src/com/cmobile/unifiedtms/web/messages.properties new file mode 100644 index 0000000..9bc0968 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/messages.properties @@ -0,0 +1,62 @@ + +application.caption = Unified TMS +application.logoLabel = Unified TMS +application.logoImage = branding/app-icon-menu.png +application.welcomeText = Welcome to Unified TMS! + +dashboard.Caption = Dashboard + +loginWindow.caption = TMS Login +loginWindow.welcomeLabel = Welcome to TMS! +loginWindow.logoImage = branding/app-icon-login.png + +menu-config.application-tms = Application +menu-config.tms_Country.browse=Countries +menu-config.tms_States.browse=States +menu-config.tms_City.browse=Cities +menu-config.tms_District.browse=Districts +menu-config.tms_MerchantType.browse=Merchant Types +menu-config.tms_Merchant.browse=Merchants +menu-config.tms_DeviceModel.browse=Device Models +menu-config.tms_TerminalGroup.browse=Terminal Groups +menu-config.tms_Terminal.browse=Terminals +menu-config.tms_Application.browse=Applications +menu-config.tms_DeviceProfile.browse=Device Profiles +menu-config.user-management=User Management +menu-config.dashboard-menu=Dashboard Settings +menu-config.tms_DownloadTask.browse=Download Tasks +menu-config.tms_TerminalLastHeartBeat.browse=Terminal Last Heart Beats +menu-config.tms_TerminalLastHeartBeat.map=Terminal Last Location +menu-config.task-menu=Tasks +menu-config.terminal-menu=Terminal +menu-config.monitoring-menu=Monitoring +menu-config.masterdata-menu=Master Data +menu-config.tms_TerminalLastDiagnosticInfo.browse=Terminal Last Diagnostic Infos +last.updated.caption=Last Update Time +menu-config.tms_DeleteTask.browse=Delete Tasks +menu-config.terminalext-management=Terminal (Extended) +menu-config.tms$Aid.browse=AID +menu-config.tms$Capk.browse=CAPK +menu-config.tms$Card.browse=BIN Range +menu-config.settings-menu=Settings +menu-config.tms$PublicKeySetting.browse=Public Key Settings +menu-config.tms$TLESetting.browse=TLE Settings +menu-config.tms_TerminalLink.browse=Terminal Links +menu-config.change-password=Change Password +menu-config.tms_TerminalProfiling=Terminal Profiling +menu-config.tms_LicenseViewer=License Viewer +menu-config.license-menu=License +menu-config.terminal-ext-browse=Terminal Ext +menu-config.tms_SimulateExceptionScreen=Simulate Exception Screen +menu-config.tms_TerminalReport.browse=Terminal Reports +menu-config.tms_TerminalGroupImport.browse=Terminal Imports +menu-config.tms_SampleChart=Sample Chart +menu-config.tms_TerminalReportNew=Terminal Report +menu-config.tms_HeartBeat.browse=Heart Beats +menu-config.tms_ResponseCode.browse=Response Codes +menu-config.terminal-link-log-browse=Terminal Link Log +menu_config.tms_HeartbeatSummary.browse=Heartbeat Summaries +menu_config.tms_VTerminalHeartBeat.browse=Heart Beats +menu_config.tms_TerminalProfiling.browse=Terminal Profilings + + diff --git a/modules/web/src/com/cmobile/unifiedtms/web/messages_id_ID.properties b/modules/web/src/com/cmobile/unifiedtms/web/messages_id_ID.properties new file mode 100644 index 0000000..f2919de --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/messages_id_ID.properties @@ -0,0 +1,5 @@ +menu-config.change-password=Ubah Password +menu-config.tms_LicenseViewer=Lihat Lisensi +menu-config.license-menu=Lisensi +menu-config.tms_TerminalGroupImport.browse=Impor Terminal +menu_config.tms_VTerminalHeartBeat.browse=Heart Beat \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web/screens/AppLoginScreen.java b/modules/web/src/com/cmobile/unifiedtms/web/screens/AppLoginScreen.java new file mode 100644 index 0000000..7082dca --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/screens/AppLoginScreen.java @@ -0,0 +1,70 @@ +package com.cmobile.unifiedtms.web.screens; + +import com.haulmont.cuba.gui.Notifications; +import com.haulmont.cuba.gui.Route; +import com.haulmont.cuba.gui.components.*; +import com.haulmont.cuba.gui.screen.*; +import com.haulmont.cuba.web.app.login.LoginScreen; +import com.haulmont.cuba.web.events.UIRefreshEvent; +import com.haulmont.cuba.web.gui.screen.ScreenDependencyUtils; +import com.vaadin.ui.Dependency; +import org.springframework.context.event.EventListener; + +import javax.inject.Inject; + + +@Route(path = "login", root = true) +@UiController("login") +@UiDescriptor("app-login-screen.xml") +public class AppLoginScreen extends LoginScreen { + + @Inject + protected HBoxLayout bottomPanel; + + @Inject + protected Label poweredByLink; + + @Subscribe + public void onAppLoginScreenInit(InitEvent event) { + loadStyles(); + + initBottomPanel(); + + // set username & password to empty + loginField.setValue(""); + passwordField.setValue(""); + } + + @EventListener + protected void onPageRefresh(UIRefreshEvent event) { + // set username & password to empty + loginField.setValue(""); + passwordField.setValue(""); + } + + @Subscribe("submit") + public void onSubmit(Action.ActionPerformedEvent event) { + login(); + } + + protected void loadStyles() { + ScreenDependencyUtils.addScreenDependency(this, + "vaadin://brand-login-screen/login.css", Dependency.Type.STYLESHEET); + } + + protected void initBottomPanel() { + if (!globalConfig.getLocaleSelectVisible()) { + poweredByLink.setAlignment(Component.Alignment.MIDDLE_CENTER); + + if (!webConfig.getLoginDialogPoweredByLinkVisible()) { + bottomPanel.setVisible(false); + } + } + } + + @Override + protected void initLogoImage() { + logoImage.setSource(RelativePathResource.class) + .setPath("VAADIN/brand-login-screen/cuba-icon-login.svg"); + } +} \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web/screens/DashboardScreen.java b/modules/web/src/com/cmobile/unifiedtms/web/screens/DashboardScreen.java new file mode 100644 index 0000000..b69ebc4 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/screens/DashboardScreen.java @@ -0,0 +1,15 @@ +package com.cmobile.unifiedtms.web.screens; + +import com.haulmont.cuba.gui.components.Window; +import com.haulmont.cuba.gui.screen.*; + +@UiController("tms_DashboardScreen") +@UiDescriptor("dashboard-screen.xml") +public class DashboardScreen extends Screen { + + @Subscribe + public void onBeforeClose(BeforeCloseEvent event) { + event.preventWindowClose(); + } + +} \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web/screens/ExtMainScreen.java b/modules/web/src/com/cmobile/unifiedtms/web/screens/ExtMainScreen.java new file mode 100644 index 0000000..736a313 --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/screens/ExtMainScreen.java @@ -0,0 +1,11 @@ +package com.cmobile.unifiedtms.web.screens; + +import com.haulmont.cuba.gui.screen.UiController; +import com.haulmont.cuba.gui.screen.UiDescriptor; +import com.haulmont.cuba.web.app.main.MainScreen; + + +@UiController("extMainScreen") +@UiDescriptor("ext-main-screen.xml") +public class ExtMainScreen extends MainScreen { +} \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web/screens/SampleChart.java b/modules/web/src/com/cmobile/unifiedtms/web/screens/SampleChart.java new file mode 100644 index 0000000..b4bc65a --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/screens/SampleChart.java @@ -0,0 +1,44 @@ +package com.cmobile.unifiedtms.web.screens; + +import com.cmobile.unifiedtms.entity.chartdata.CountryGrowth; +import com.haulmont.cuba.gui.model.CollectionContainer; +import com.haulmont.cuba.gui.screen.Screen; +import com.haulmont.cuba.gui.screen.Subscribe; +import com.haulmont.cuba.gui.screen.UiController; +import com.haulmont.cuba.gui.screen.UiDescriptor; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; + +@UiController("tms_SampleChart") +@UiDescriptor("sample-chart.xml") +public class SampleChart extends Screen { + + @Inject + private CollectionContainer countryGrowthDc; + + @Subscribe + private void onInit(InitEvent event) { + List items = new ArrayList<>(); + items.add(countryGrowth("USA", 3.5, 4.2)); + items.add(countryGrowth("UK", 1.7, 3.1)); + items.add(countryGrowth("Canada", 2.8, 2.9)); + items.add(countryGrowth("Japan", 2.6, 2.3)); + items.add(countryGrowth("France", 1.4, 2.1)); + items.add(countryGrowth("Brazil", 2.6, 4.9)); + items.add(countryGrowth("Russia", 6.4, 7.2)); + items.add(countryGrowth("India", 8.0, 7.1)); + items.add(countryGrowth("China", 9.9, 10.1)); + countryGrowthDc.setItems(items); + } + + private CountryGrowth countryGrowth(String country, double year2014, double year2015) { + CountryGrowth cg = new CountryGrowth(); + cg.setCountry(country); + cg.setYear2014(year2014); + cg.setYear2015(year2015); + return cg; + } + +} \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web/screens/SimulateExceptionScreen.java b/modules/web/src/com/cmobile/unifiedtms/web/screens/SimulateExceptionScreen.java new file mode 100644 index 0000000..b5224eb --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/screens/SimulateExceptionScreen.java @@ -0,0 +1,16 @@ +package com.cmobile.unifiedtms.web.screens; + +import com.haulmont.cuba.gui.screen.Screen; +import com.haulmont.cuba.gui.screen.Subscribe; +import com.haulmont.cuba.gui.screen.UiController; +import com.haulmont.cuba.gui.screen.UiDescriptor; + +@UiController("tms_SimulateExceptionScreen") +@UiDescriptor("simulate-exception-screen.xml") +public class SimulateExceptionScreen extends Screen { + @Subscribe + public void onAfterInit(AfterInitEvent event) { + throw new RuntimeException("Simulated Exception. Can you see the stack trace?", + new IllegalArgumentException("IllegalArgumentException nested stack trace.")); + } +} \ No newline at end of file diff --git a/modules/web/src/com/cmobile/unifiedtms/web/screens/app-login-screen.xml b/modules/web/src/com/cmobile/unifiedtms/web/screens/app-login-screen.xml new file mode 100644 index 0000000..5bbc23d --- /dev/null +++ b/modules/web/src/com/cmobile/unifiedtms/web/screens/app-login-screen.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + +