diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/CygnusCloudServiceApplication.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/CygnusCloudServiceApplication.class
index 7232b49..801c4eb 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/CygnusCloudServiceApplication.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/CygnusCloudServiceApplication.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/CacheProperties.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/CacheProperties.class
index 14d9048..cc07f55 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/CacheProperties.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/CacheProperties.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/ReactiveCacheService.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/ReactiveCacheService.class
index 282b21a..75bbc1b 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/ReactiveCacheService.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/cache/ReactiveCacheService.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/DatabaseProperties.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/DatabaseProperties.class
index 002d601..64bd9cb 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/DatabaseProperties.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/DatabaseProperties.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/ReactiveDatabaseClient.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/ReactiveDatabaseClient.class
index 2c39e49..40645cd 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/ReactiveDatabaseClient.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/ReactiveDatabaseClient.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/VertxDatabaseConfiguration.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/VertxDatabaseConfiguration.class
index 9842cb4..2149851 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/VertxDatabaseConfiguration.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/database/VertxDatabaseConfiguration.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/CloudLoginController.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/CloudLoginController.class
index ab20dfd..96577c4 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/CloudLoginController.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/CloudLoginController.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/EncryptedLoginRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/EncryptedLoginRequest.class
index e0697fb..57beea7 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/EncryptedLoginRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/EncryptedLoginRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/IdentityErrorHandler.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/IdentityErrorHandler.class
index 199276c..6348aae 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/IdentityErrorHandler.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/IdentityErrorHandler.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginEncryptionProperties.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginEncryptionProperties.class
index 720fb0a..9ffa7bc 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginEncryptionProperties.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginEncryptionProperties.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginPayload.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginPayload.class
index 036d227..e93d93f 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginPayload.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/LoginPayload.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/RsaLoginPayloadDecryptor.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/RsaLoginPayloadDecryptor.class
index c7344c3..41cf73c 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/RsaLoginPayloadDecryptor.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/api/RsaLoginPayloadDecryptor.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/AuthenticatedIdentity.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/AuthenticatedIdentity.class
index 49fc6dd..9f47ce9 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/AuthenticatedIdentity.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/AuthenticatedIdentity.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/IdentityUser.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/IdentityUser.class
index 0083642..e1ebe7a 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/IdentityUser.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/IdentityUser.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/MenuItem.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/MenuItem.class
index ea03570..2c7384e 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/MenuItem.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/model/MenuItem.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRepository.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRepository.class
index 008de9a..8468cc7 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRepository.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRepository.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRowMapper.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRowMapper.class
index cda91da..940864b 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRowMapper.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/repository/IdentityRowMapper.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/AuthenticationException.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/AuthenticationException.class
index b17d372..cbba308 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/AuthenticationException.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/AuthenticationException.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/IdentityAuthenticationService.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/IdentityAuthenticationService.class
index 2d7d149..4c89559 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/IdentityAuthenticationService.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/IdentityAuthenticationService.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifier.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifier.class
index c72e3e9..a5274af 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifier.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifier.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LoginRequestReplayService.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LoginRequestReplayService.class
index d382a24..8637ef2 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LoginRequestReplayService.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/identity/service/LoginRequestReplayService.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AccessTokenIssuer.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AccessTokenIssuer.class
index 903c7cd..10708be 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AccessTokenIssuer.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AccessTokenIssuer.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AudienceValidator.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AudienceValidator.class
index 9cfa8ae..2ec1eba 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AudienceValidator.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/AudienceValidator.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/ClientAssertionValidator.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/ClientAssertionValidator.class
index 929c6fa..229fb21 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/ClientAssertionValidator.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/ClientAssertionValidator.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CloudSecurityConfiguration.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CloudSecurityConfiguration.class
index 0592fc5..00de284 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CloudSecurityConfiguration.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CloudSecurityConfiguration.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CommunicationSecurityProperties.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CommunicationSecurityProperties.class
index 00d66d3..e965d3a 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CommunicationSecurityProperties.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/CommunicationSecurityProperties.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/JwtReplayProtectionService.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/JwtReplayProtectionService.class
index afa553c..0d152c4 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/JwtReplayProtectionService.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/JwtReplayProtectionService.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineAuthenticationException.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineAuthenticationException.class
index bb5b347..41d4cc5 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineAuthenticationException.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineAuthenticationException.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineClientPrincipal.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineClientPrincipal.class
index cbbe4a0..0cf1d72 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineClientPrincipal.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineClientPrincipal.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineSecurityConfigurationValidator.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineSecurityConfigurationValidator.class
index 3d4e646..b8cceb6 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineSecurityConfigurationValidator.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineSecurityConfigurationValidator.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenController.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenController.class
index b03152a..fbe0607 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenController.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenController.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenErrorHandler.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenErrorHandler.class
index e05b867..f2af0a0 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenErrorHandler.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/MachineTokenErrorHandler.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/PemKeyLoader.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/PemKeyLoader.class
index fc899d3..02611e1 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/PemKeyLoader.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/PemKeyLoader.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/TokenResponse.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/TokenResponse.class
index 5937c7f..1469b25 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/TokenResponse.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/security/TokenResponse.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemConfiguration.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemConfiguration.class
index 872d50d..64c4175 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemConfiguration.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemConfiguration.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoController.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoController.class
index 683f7eb..33bfdff 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoController.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoController.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoResponse.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoResponse.class
index 1610c7d..afc2748 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoResponse.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/system/SystemInfoResponse.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationRequest.class
index c85bdf3..3faf027 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationResponse.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationResponse.class
index 5fbac16..acf89d2 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationResponse.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/ActivationValidationResponse.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateClientRegistrationRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateClientRegistrationRequest.class
index 9d3bb8a..5ba95f6 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateClientRegistrationRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateClientRegistrationRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateLicenseRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateLicenseRequest.class
index f3fc207..8c8c10f 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateLicenseRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateLicenseRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateTenantRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateTenantRequest.class
index 9ef4c1b..f0a4430 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateTenantRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/CreateTenantRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationController.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationController.class
index 5a48e26..a1255ba 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationController.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationController.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationErrorHandler.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationErrorHandler.class
index 8acf66d..f6f31f0 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationErrorHandler.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationActivationErrorHandler.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationRegistrationRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationRegistrationRequest.class
index d96f42d..0b86d86 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationRegistrationRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/InstallationRegistrationRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/IssueLicenseKeyRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/IssueLicenseKeyRequest.class
index bcda0a2..401395d 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/IssueLicenseKeyRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/IssueLicenseKeyRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/RetireInstallationRequest.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/RetireInstallationRequest.class
index 76059c2..a89a030 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/RetireInstallationRequest.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/api/RetireInstallationRequest.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationKeyStatus.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationKeyStatus.class
index 2c22d81..8a3cf81 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationKeyStatus.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationKeyStatus.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationSession.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationSession.class
index ac29f97..0940144 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationSession.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ActivationSession.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientAccount.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientAccount.class
index 4c7a1a4..9510d31 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientAccount.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientAccount.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientInstallation.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientInstallation.class
index d36b9d6..2830f1a 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientInstallation.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientInstallation.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientLicense.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientLicense.class
index 17c1404..292baf7 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientLicense.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientLicense.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientRegistration.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientRegistration.class
index e788b98..a9520f9 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientRegistration.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientRegistration.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientStatus.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientStatus.class
index 2edcf80..10d3167 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientStatus.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/ClientStatus.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/InstallationLifecycleResult.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/InstallationLifecycleResult.class
index 160c4d9..240cdc3 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/InstallationLifecycleResult.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/InstallationLifecycleResult.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/IssuedLicenseKey.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/IssuedLicenseKey.class
index 90f28d7..60f9d91 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/IssuedLicenseKey.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/IssuedLicenseKey.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationContext.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationContext.class
index 8b25d52..ec0b7a5 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationContext.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationContext.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationKey.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationKey.class
index 85f08ed..e55ecfb 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationKey.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseActivationKey.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseDeliveryDetails.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseDeliveryDetails.class
index 83e5e57..5669a5c 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseDeliveryDetails.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseDeliveryDetails.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseStatus.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseStatus.class
index f2f2535..079c0fb 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseStatus.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/LicenseStatus.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegisteredInstallation.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegisteredInstallation.class
index f83d393..99198e5 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegisteredInstallation.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegisteredInstallation.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegistrationStatus.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegistrationStatus.class
index 7714783..2bf1e6d 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegistrationStatus.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/model/RegistrationStatus.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/ClientAdministrationRepository.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/ClientAdministrationRepository.class
index efa25a7..9b42c53 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/ClientAdministrationRepository.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/ClientAdministrationRepository.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository$RegistrationContext.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository$RegistrationContext.class
index fb5ab3f..7f71061 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository$RegistrationContext.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository$RegistrationContext.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository.class
index e229fbd..c86ee28 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationActivationRepository.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationLifecycleRepository.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationLifecycleRepository.class
index 9564477..2ca68af 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationLifecycleRepository.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/InstallationLifecycleRepository.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/TenantRegistrationRepository.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/TenantRegistrationRepository.class
index 60c07b9..87ff3e9 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/TenantRegistrationRepository.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/repository/TenantRegistrationRepository.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimitException.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimitException.class
index 14e21f6..bd6a0f0 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimitException.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimitException.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimiter.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimiter.class
index 6eb31cd..b7b81da 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimiter.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/ActivationRateLimiter.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationActivationException.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationActivationException.class
index 6fef5c0..5cd967e 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationActivationException.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationActivationException.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationLifecycleService.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationLifecycleService.class
index 5d837f4..cc9ea2f 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationLifecycleService.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/InstallationLifecycleService.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/LicenseKeyException.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/LicenseKeyException.class
index c61f076..e53a6b7 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/LicenseKeyException.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/LicenseKeyException.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/RegistrationEmailService.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/RegistrationEmailService.class
index 086146b..0e3a490 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/RegistrationEmailService.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/RegistrationEmailService.class differ
diff --git a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/TenantRegistrationService.class b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/TenantRegistrationService.class
index 0771967..3ec46f4 100644
Binary files a/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/TenantRegistrationService.class and b/cygnus-cloud-service/target/classes/com/cygnus/cloud/tenant/service/TenantRegistrationService.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/InfrastructureConfigurationTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/InfrastructureConfigurationTest.class
index 8c135e0..32d7ad0 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/InfrastructureConfigurationTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/InfrastructureConfigurationTest.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/IdentityAuthenticationServiceTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/IdentityAuthenticationServiceTest.class
index d1437d7..e84e81d 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/IdentityAuthenticationServiceTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/IdentityAuthenticationServiceTest.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifierTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifierTest.class
index 81087e1..6bb4e0c 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifierTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/identity/service/LegacyPasswordVerifierTest.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/security/MachineTokenFlowTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/security/MachineTokenFlowTest.class
index e3f6f27..e20fa52 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/security/MachineTokenFlowTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/security/MachineTokenFlowTest.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest$FixedClockConfiguration.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest$FixedClockConfiguration.class
index 8828acf..12451cc 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest$FixedClockConfiguration.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest$FixedClockConfiguration.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest.class
index 629a7d6..551275e 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/system/SystemInfoControllerTest.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/model/ClientLicenseTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/model/ClientLicenseTest.class
index 555bc71..4ad8e4a 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/model/ClientLicenseTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/model/ClientLicenseTest.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/ActivationRateLimiterTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/ActivationRateLimiterTest.class
index 5dee220..be11c05 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/ActivationRateLimiterTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/ActivationRateLimiterTest.class differ
diff --git a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/TenantRegistrationServiceTest.class b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/TenantRegistrationServiceTest.class
index de5d2d9..fc1a752 100644
Binary files a/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/TenantRegistrationServiceTest.class and b/cygnus-cloud-service/target/test-classes/com/cygnus/cloud/tenant/service/TenantRegistrationServiceTest.class differ
diff --git a/cygnus-installer/README.md b/cygnus-installer/README.md
index 2cdc751..ba3b2cd 100644
--- a/cygnus-installer/README.md
+++ b/cygnus-installer/README.md
@@ -1,26 +1,83 @@
-# Cygnus installation wizard
+# Technobee Service Installer
-The wizard validates Docker, activates a client license, generates a unique
-3072-bit installation signing key, registers the installation, and writes the
-deployment files. The license key is never persisted.
+One Swing-based Java installer supports Matrix and Cygnus through an external
+INI product profile. It never connects to PostgreSQL or Redis. The selected
+product cloud service validates the activation key and registers the
+installation.
+
+## Build and run
```bash
-java -jar target/cygnus-installer-1.0.0-SNAPSHOT.jar
+mvn -pl cygnus-installer -am package
+TECHNOBEE_INSTALLER_CONFIG=cygnus-installer/config/matrix-installer.ini \
+java -jar cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar
```
-Set `CYGNUS_CLOUD_URL` before execution. The wizard asks where deployment
-files should be written and offers `CYGNUS_INSTALL_OUTPUT` as the default.
+Use `config/cygnus-installer.ini` for Cygnus. Before production use, set the
+cloud URL and the cloud assertion-encryption public-key path in the selected
+INI. Both profiles use these cloud endpoints by default:
-The selected output directory contains:
+- `POST /api/v1/installations/activation/validate`
+- `POST /api/v1/installations/register`
+
+The desktop wizard is the default. It checks Docker, collects activation and
+installation details, lets the user choose an output directory, and reports
+installation progress. For servers without a desktop or for automation, append
+`--cli` to retain the interactive terminal workflow:
+
+```bash
+TECHNOBEE_INSTALLER_CONFIG=cygnus-installer/config/matrix-installer.ini \
+java -jar cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar --cli
+```
+
+## Configuration
+
+```ini
+[installer]
+product=matrix
+cloud_service_url=https://cloud.example.com
+installer_api_base_path=/api/v1/installations
+environment=production
+output_directory=./matrix-installation
+
+[profile.matrix]
+display_name=Matrix
+service_name=matrix-onprem
+image_environment_variable=MATRIX_IMAGE
+configuration_root=matrix
+configuration_file_name=installation.yml
+installation_config_environment_variable=MATRIX_INSTALLATION_CONFIG
+container_configuration_path=/opt/matrix/config/installation.yml
+token_path=/oauth2/token
+assertion_encryption_public_key=/secure/cloud-assertion-public.pem
+optional_fields=
+```
+
+The installer validates the product, URL, API path, environment, profile
+values, and public-key file before asking installation questions.
+
+## Generated output
```text
+.env
compose.yml
config/
installation.yml
+ machine-assertion.jwt
keys/
client-signing-private.pem
client-signing-public.pem
```
-The private key is created with owner-only permissions on POSIX systems. The
-plaintext installation license key is never written to the output directory.
+The installer asks for the product Docker image, validates it, and stores it
+under the profile's image variable in `.env`. Docker Compose loads this file
+automatically, so no separate `export MATRIX_IMAGE` or `export CYGNUS_IMAGE`
+step is required.
+
+The RSA-3072 pair is generated locally. Only the public key is sent during
+registration. The private key and encrypted machine assertion remain on
+premises and receive owner-only permissions on POSIX systems. The activation
+key is never written to disk.
+
+`scripts/setup-local-communication.sh` remains a development/provisioning
+utility; it is not used by this installer.
diff --git a/cygnus-installer/config/cygnus-installer.ini b/cygnus-installer/config/cygnus-installer.ini
new file mode 100644
index 0000000..b3280e9
--- /dev/null
+++ b/cygnus-installer/config/cygnus-installer.ini
@@ -0,0 +1,18 @@
+[installer]
+product=cygnus
+cloud_service_url=http://localhost:8090
+installer_api_base_path=/api/v1/installations
+environment=production
+output_directory=./cygnus-installation
+
+[profile.cygnus]
+display_name=Cygnus
+service_name=cygnus-onprem
+image_environment_variable=CYGNUS_IMAGE
+configuration_root=cygnus
+configuration_file_name=installation.yml
+installation_config_environment_variable=CYGNUS_INSTALLATION_CONFIG
+container_configuration_path=/opt/cygnus/config/installation.yml
+token_path=/oauth2/token
+assertion_encryption_public_key=../../config/keys/assertion-decryption-public.pem
+optional_fields=
diff --git a/cygnus-installer/config/matrix-installer.ini b/cygnus-installer/config/matrix-installer.ini
new file mode 100644
index 0000000..e75776a
--- /dev/null
+++ b/cygnus-installer/config/matrix-installer.ini
@@ -0,0 +1,18 @@
+[installer]
+product=matrix
+cloud_service_url=http://localhost:8090
+installer_api_base_path=/api/v1/installations
+environment=production
+output_directory=./matrix-installation
+
+[profile.matrix]
+display_name=Matrix
+service_name=matrix-onprem
+image_environment_variable=MATRIX_IMAGE
+configuration_root=matrix
+configuration_file_name=installation.yml
+installation_config_environment_variable=MATRIX_INSTALLATION_CONFIG
+container_configuration_path=/opt/matrix/config/installation.yml
+token_path=/oauth2/token
+assertion_encryption_public_key=../../config/keys/assertion-decryption-public.pem
+optional_fields=
diff --git a/cygnus-installer/pom.xml b/cygnus-installer/pom.xml
index 358c8ee..8d1a442 100644
--- a/cygnus-installer/pom.xml
+++ b/cygnus-installer/pom.xml
@@ -9,8 +9,8 @@
1.0.0-SNAPSHOT
../pom.xml
- cygnus-installer
- Cygnus Installation Wizard
+ technobee-service-installer
+ Technobee Service Installer
@@ -27,6 +27,11 @@
org.springframework.boot
spring-boot-starter-webflux
+
+ com.nimbusds
+ nimbus-jose-jwt
+ ${nimbus.version}
+
org.springframework.boot
spring-boot-starter-webflux-test
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/ActivationClient.java b/cygnus-installer/src/main/java/com/cygnus/installer/ActivationClient.java
index 634b299..84aa7bc 100644
--- a/cygnus-installer/src/main/java/com/cygnus/installer/ActivationClient.java
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/ActivationClient.java
@@ -8,9 +8,11 @@ import org.springframework.web.reactive.function.client.WebClient;
public class ActivationClient {
private final WebClient webClient;
+ private final InstallerSettings settings;
- public ActivationClient(WebClient webClient) {
+ public ActivationClient(WebClient webClient, InstallerSettings settings) {
this.webClient = webClient;
+ this.settings = settings;
}
public ActivationDtos.ValidationResponse validate(
@@ -19,7 +21,7 @@ public class ActivationClient {
UUID installationUuid,
String installerVersion) {
return webClient.post()
- .uri("/api/v1/installations/activation/validate")
+ .uri(settings.validationPath())
.bodyValue(new ActivationDtos.ValidationRequest(
clientCode, licenseKey, installationUuid, installerVersion))
.retrieve()
@@ -35,7 +37,7 @@ public class ActivationClient {
String softwareVersion,
String environment) {
return webClient.post()
- .uri("/api/v1/installations/register")
+ .uri(settings.registrationPath())
.bodyValue(new ActivationDtos.RegistrationRequest(
validation.activationToken(),
installationCode,
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/ActivationDtos.java b/cygnus-installer/src/main/java/com/cygnus/installer/ActivationDtos.java
index 8018e60..19a1cba 100644
--- a/cygnus-installer/src/main/java/com/cygnus/installer/ActivationDtos.java
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/ActivationDtos.java
@@ -30,8 +30,10 @@ final class ActivationDtos {
record RegistrationResponse(
UUID installationId,
+ UUID installationUuid,
UUID tenantId,
- UUID clientId,
+ String clientId,
String installationCode,
+ int securityVersion,
String status) {}
}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/CygnusInstallerApplication.java b/cygnus-installer/src/main/java/com/cygnus/installer/CygnusInstallerApplication.java
deleted file mode 100644
index 695abd8..0000000
--- a/cygnus-installer/src/main/java/com/cygnus/installer/CygnusInstallerApplication.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.cygnus.installer;
-
-import org.springframework.boot.CommandLineRunner;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.WebApplicationType;
-
-@SpringBootApplication
-public class CygnusInstallerApplication implements CommandLineRunner {
-
- private final InstallationWizard wizard;
-
- public CygnusInstallerApplication(InstallationWizard wizard) {
- this.wizard = wizard;
- }
-
- public static void main(String[] args) {
- SpringApplication application = new SpringApplication(CygnusInstallerApplication.class);
- application.setWebApplicationType(WebApplicationType.NONE);
- System.exit(SpringApplication.exit(application.run(args)));
- }
-
- @Override
- public void run(String... args) {
- wizard.run();
- }
-}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/DeploymentWriter.java b/cygnus-installer/src/main/java/com/cygnus/installer/DeploymentWriter.java
index 6647b2d..e21b60a 100644
--- a/cygnus-installer/src/main/java/com/cygnus/installer/DeploymentWriter.java
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/DeploymentWriter.java
@@ -1,9 +1,12 @@
package com.cygnus.installer;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Map;
import java.util.UUID;
import org.springframework.stereotype.Service;
@@ -14,55 +17,161 @@ public class DeploymentWriter {
Path output,
UUID installationUuid,
String installationCode,
+ String clientId,
ActivationDtos.ValidationResponse validation,
ActivationDtos.RegistrationResponse registration,
InstallationKeyPair keys,
- String cloudUrl) {
+ String machineAssertion,
+ InstallerSettings settings,
+ ProductProfile profile,
+ String dockerImage,
+ Map optionalFields) {
try {
- Path config = output.resolve("config");
+ Path normalizedOutput = output.toAbsolutePath().normalize();
+ Path config = normalizedOutput.resolve("config");
Path keyDirectory = config.resolve("keys");
Files.createDirectories(keyDirectory);
- writePrivate(keyDirectory.resolve("client-signing-private.pem"), keys.privateKeyPem());
- Files.writeString(
- keyDirectory.resolve("client-signing-public.pem"), keys.publicKeyPem());
- Files.writeString(config.resolve("installation.yml"), """
- cygnus:
- cloud-url: "%s"
- tenant-id: "%s"
- client-id: "%s"
- installation-id: "%s"
- installation-uuid: "%s"
- installation-code: "%s"
- signing-private-key: "file:./config/keys/client-signing-private.pem"
- """.formatted(
- cloudUrl,
- validation.tenantId(),
- registration.clientId(),
- registration.installationId(),
- installationUuid,
- installationCode));
- Files.writeString(output.resolve("compose.yml"), """
- services:
- cygnus-onprem:
- image: ${CYGNUS_IMAGE:?Set CYGNUS_IMAGE}
- restart: unless-stopped
- volumes:
- - ./config:/opt/cygnus/config:ro
- environment:
- CYGNUS_INSTALLATION_CONFIG: /opt/cygnus/config/installation.yml
- """);
- return output;
- } catch (IOException e) {
- throw new IllegalStateException("Could not write installation files", e);
+
+ String privateRelative = "config/keys/client-signing-private.pem";
+ String publicRelative = "config/keys/client-signing-public.pem";
+ String assertionRelative = "config/machine-assertion.jwt";
+ writePrivate(
+ normalizedOutput.resolve(privateRelative),
+ keys.privateKeyPem());
+ writePublic(
+ normalizedOutput.resolve(publicRelative),
+ keys.publicKeyPem());
+ writePrivate(
+ normalizedOutput.resolve(assertionRelative),
+ machineAssertion);
+ writePublic(
+ config.resolve(profile.configurationFileName()),
+ installationConfiguration(
+ installationUuid,
+ installationCode,
+ clientId,
+ validation,
+ registration,
+ settings,
+ profile,
+ privateRelative,
+ publicRelative,
+ assertionRelative,
+ optionalFields));
+ writePublic(
+ normalizedOutput.resolve("compose.yml"),
+ compose(profile));
+ writePrivate(
+ normalizedOutput.resolve(".env"),
+ profile.imageEnvironmentVariable() + "=" + dockerImage + "\n");
+ return normalizedOutput;
+ } catch (IOException exception) {
+ throw new IllegalStateException("Could not write installation files", exception);
}
}
+ private String installationConfiguration(
+ UUID installationUuid,
+ String installationCode,
+ String clientId,
+ ActivationDtos.ValidationResponse validation,
+ ActivationDtos.RegistrationResponse registration,
+ InstallerSettings settings,
+ ProductProfile profile,
+ String privateKey,
+ String publicKey,
+ String assertion,
+ Map optionalFields) {
+ StringBuilder yaml = new StringBuilder()
+ .append(profile.configurationRoot()).append(":\n")
+ .append(" product: ").append(quoted(profile.product())).append('\n')
+ .append(" cloud-url: ")
+ .append(quoted(settings.cloudServiceUrl().toString())).append('\n')
+ .append(" token-url: ")
+ .append(quoted(settings.cloudServiceUrl() + profile.tokenPath())).append('\n')
+ .append(" tenant-id: ").append(quoted(value(validation.tenantId()))).append('\n')
+ .append(" client-id: ").append(quoted(clientId)).append('\n')
+ .append(" installation-id: ")
+ .append(quoted(value(registration.installationId()))).append('\n')
+ .append(" installation-uuid: ")
+ .append(quoted(installationUuid.toString())).append('\n')
+ .append(" installation-code: ").append(quoted(installationCode)).append('\n')
+ .append(" environment: ").append(quoted(settings.environment())).append('\n')
+ .append(" machine-assertion: ").append(quoted("file:./" + assertion)).append('\n')
+ .append(" signing-private-key: ").append(quoted("file:./" + privateKey)).append('\n')
+ .append(" signing-public-key: ").append(quoted("file:./" + publicKey)).append('\n');
+ if (!optionalFields.isEmpty()) {
+ yaml.append(" installation-fields:\n");
+ optionalFields.forEach((key, value) -> yaml
+ .append(" ").append(key).append(": ").append(quoted(value)).append('\n'));
+ }
+ return yaml.toString();
+ }
+
+ private String compose(ProductProfile profile) {
+ Path containerConfiguration = Path.of(profile.containerConfigurationPath());
+ Path containerConfigDirectory = containerConfiguration.getParent();
+ if (containerConfigDirectory == null) {
+ throw new InstallerConfigurationException(
+ "Profile container_configuration_path must include a directory");
+ }
+ return """
+ services:
+ %s:
+ image: ${%s:?Set %s}
+ restart: unless-stopped
+ volumes:
+ - ./config:%s:ro
+ environment:
+ %s: %s
+ """.formatted(
+ profile.serviceName(),
+ profile.imageEnvironmentVariable(),
+ profile.imageEnvironmentVariable(),
+ containerConfigDirectory,
+ profile.installationConfigEnvironmentVariable(),
+ profile.containerConfigurationPath());
+ }
+
+ private String quoted(String value) {
+ if (value == null) {
+ return "\"\"";
+ }
+ return '"' + value
+ .replace("\\", "\\\\")
+ .replace("\"", "\\\"")
+ .replace("\r", "")
+ .replace("\n", "\\n") + '"';
+ }
+
+ private String value(Object value) {
+ return value == null ? "" : value.toString();
+ }
+
private void writePrivate(Path path, String content) throws IOException {
- Files.writeString(path, content);
+ Files.createDirectories(path.getParent());
+ Files.writeString(
+ path,
+ content,
+ StandardCharsets.US_ASCII,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING,
+ StandardOpenOption.WRITE);
try {
Files.setPosixFilePermissions(path, PosixFilePermissions.fromString("rw-------"));
} catch (UnsupportedOperationException ignored) {
- // Non-POSIX platforms use their native ACLs.
+ // Non-POSIX platforms use native ACLs.
}
}
+
+ private void writePublic(Path path, String content) throws IOException {
+ Files.createDirectories(path.getParent());
+ Files.writeString(
+ path,
+ content,
+ StandardCharsets.UTF_8,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING,
+ StandardOpenOption.WRITE);
+ }
}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/IniConfigurationLoader.java b/cygnus-installer/src/main/java/com/cygnus/installer/IniConfigurationLoader.java
new file mode 100644
index 0000000..8b414b5
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/IniConfigurationLoader.java
@@ -0,0 +1,119 @@
+package com.cygnus.installer;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import org.springframework.stereotype.Component;
+
+@Component
+public class IniConfigurationLoader {
+
+ private static final Set PRODUCTS = Set.of("matrix", "cygnus");
+
+ public InstallerSettings load(Path path, String installerVersion) {
+ IniDocument ini = parse(path);
+ String product = ini.required("installer", "product").toLowerCase(Locale.ROOT);
+ if (!PRODUCTS.contains(product)) {
+ throw new InstallerConfigurationException(
+ "Unsupported product '" + product + "'. Expected matrix or cygnus");
+ }
+ URI cloudUri = absoluteHttpUri(ini.required("installer", "cloud_service_url"));
+ String apiBasePath = normalizedApiPath(
+ ini.required("installer", "installer_api_base_path"));
+ String environment = ini.required("installer", "environment");
+ String output = ini.optional(
+ "installer", "output_directory", "./" + product + "-installation");
+ return new InstallerSettings(
+ product,
+ cloudUri,
+ apiBasePath,
+ environment,
+ Path.of(output),
+ path.toAbsolutePath().normalize().getParent(),
+ installerVersion,
+ ini);
+ }
+
+ IniDocument parse(Path path) {
+ if (path == null || !Files.isRegularFile(path)) {
+ throw new InstallerConfigurationException(
+ "Installer INI file was not found: " + path);
+ }
+ Map> sections = new LinkedHashMap<>();
+ String currentSection = null;
+ try {
+ int lineNumber = 0;
+ for (String rawLine : Files.readAllLines(path)) {
+ lineNumber++;
+ String line = rawLine.trim();
+ if (line.isEmpty() || line.startsWith("#") || line.startsWith(";")) {
+ continue;
+ }
+ if (line.startsWith("[") && line.endsWith("]")) {
+ currentSection = line.substring(1, line.length() - 1)
+ .trim()
+ .toLowerCase(Locale.ROOT);
+ if (currentSection.isBlank()) {
+ throw malformed(path, lineNumber);
+ }
+ sections.computeIfAbsent(currentSection, ignored -> new LinkedHashMap<>());
+ continue;
+ }
+ int separator = line.indexOf('=');
+ if (currentSection == null || separator < 1) {
+ throw malformed(path, lineNumber);
+ }
+ String key = line.substring(0, separator).trim().toLowerCase(Locale.ROOT);
+ String value = line.substring(separator + 1).trim();
+ if (key.isBlank()) {
+ throw malformed(path, lineNumber);
+ }
+ sections.get(currentSection).put(key, value);
+ }
+ return new IniDocument(sections);
+ } catch (IOException exception) {
+ throw new InstallerConfigurationException(
+ "Unable to read installer INI file: " + path, exception);
+ }
+ }
+
+ private URI absoluteHttpUri(String value) {
+ try {
+ URI uri = URI.create(value);
+ if (!uri.isAbsolute()
+ || !("http".equalsIgnoreCase(uri.getScheme())
+ || "https".equalsIgnoreCase(uri.getScheme()))
+ || uri.getHost() == null
+ || uri.getQuery() != null
+ || uri.getFragment() != null) {
+ throw new IllegalArgumentException();
+ }
+ return URI.create(value.replaceAll("/+$", ""));
+ } catch (IllegalArgumentException exception) {
+ throw new InstallerConfigurationException(
+ "cloud_service_url must be an absolute http(s) URL");
+ }
+ }
+
+ private String normalizedApiPath(String value) {
+ String path = value.trim().replaceAll("/+$", "");
+ if (!path.startsWith("/")
+ || path.contains("..")
+ || path.contains("?")
+ || path.contains("#")) {
+ throw new InstallerConfigurationException(
+ "installer_api_base_path must be an absolute safe URL path");
+ }
+ return path;
+ }
+
+ private InstallerConfigurationException malformed(Path path, int line) {
+ return new InstallerConfigurationException(
+ "Malformed INI configuration at " + path + ":" + line);
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/IniDocument.java b/cygnus-installer/src/main/java/com/cygnus/installer/IniDocument.java
new file mode 100644
index 0000000..33cf098
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/IniDocument.java
@@ -0,0 +1,29 @@
+package com.cygnus.installer;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+final class IniDocument {
+ private final Map> sections;
+
+ IniDocument(Map> sections) {
+ Map> copy = new LinkedHashMap<>();
+ sections.forEach((name, values) ->
+ copy.put(name, Collections.unmodifiableMap(new LinkedHashMap<>(values))));
+ this.sections = Collections.unmodifiableMap(copy);
+ }
+
+ String required(String section, String key) {
+ String value = optional(section, key, null);
+ if (value == null || value.isBlank()) {
+ throw new InstallerConfigurationException(
+ "Missing required INI setting [" + section + "] " + key);
+ }
+ return value;
+ }
+
+ String optional(String section, String key, String defaultValue) {
+ return sections.getOrDefault(section, Map.of()).getOrDefault(key, defaultValue);
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallationProgressListener.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationProgressListener.java
new file mode 100644
index 0000000..c68684e
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationProgressListener.java
@@ -0,0 +1,6 @@
+package com.cygnus.installer;
+
+@FunctionalInterface
+public interface InstallationProgressListener {
+ void update(int percentage, String message);
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallationRequest.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationRequest.java
new file mode 100644
index 0000000..3bd15af
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationRequest.java
@@ -0,0 +1,18 @@
+package com.cygnus.installer;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+public record InstallationRequest(
+ String clientCode,
+ String licenseKey,
+ String installationCode,
+ String installationName,
+ String dockerImage,
+ Path outputDirectory,
+ Map optionalFields) {
+
+ public InstallationRequest {
+ optionalFields = optionalFields == null ? Map.of() : Map.copyOf(optionalFields);
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallationResult.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationResult.java
new file mode 100644
index 0000000..d22d2a8
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationResult.java
@@ -0,0 +1,10 @@
+package com.cygnus.installer;
+
+import java.nio.file.Path;
+import java.util.UUID;
+
+public record InstallationResult(
+ UUID installationId,
+ String installationCode,
+ String clientId,
+ Path outputDirectory) {}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallationService.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationService.java
new file mode 100644
index 0000000..6b5b8a7
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationService.java
@@ -0,0 +1,125 @@
+package com.cygnus.installer;
+
+import java.nio.file.Path;
+import java.util.UUID;
+import org.springframework.stereotype.Service;
+
+@Service
+public class InstallationService {
+
+ private final DockerPrerequisiteChecker prerequisites;
+ private final ActivationClient activationClient;
+ private final InstallationKeyService keyService;
+ private final MachineAssertionService assertionService;
+ private final DeploymentWriter deploymentWriter;
+ private final InstallerSettings settings;
+ private final ProductProfile profile;
+
+ public InstallationService(
+ DockerPrerequisiteChecker prerequisites,
+ ActivationClient activationClient,
+ InstallationKeyService keyService,
+ MachineAssertionService assertionService,
+ DeploymentWriter deploymentWriter,
+ InstallerSettings settings,
+ ProductProfile profile) {
+ this.prerequisites = prerequisites;
+ this.activationClient = activationClient;
+ this.keyService = keyService;
+ this.assertionService = assertionService;
+ this.deploymentWriter = deploymentWriter;
+ this.settings = settings;
+ this.profile = profile;
+ }
+
+ public void verifyPrerequisites() {
+ prerequisites.verify();
+ }
+
+ public InstallationResult install(
+ InstallationRequest request,
+ InstallationProgressListener progress) {
+ validate(request);
+ progress.update(5, "Checking Docker prerequisites");
+ prerequisites.verify();
+
+ UUID installationUuid = UUID.randomUUID();
+ progress.update(20, "Validating activation key");
+ var validation = activationClient.validate(
+ request.clientCode().trim(),
+ request.licenseKey(),
+ installationUuid,
+ settings.installerVersion());
+
+ progress.update(40, "Generating local RSA signing keys");
+ var keys = keyService.generate();
+
+ progress.update(58, "Registering installation with "
+ + profile.displayName() + " cloud service");
+ var registration = activationClient.register(
+ validation,
+ request.installationCode().trim(),
+ request.installationName().trim(),
+ keys.publicKeyPem(),
+ settings.installerVersion(),
+ settings.environment());
+ String clientId = registration.clientId() == null
+ || registration.clientId().isBlank()
+ ? validation.tenantSlug()
+ : registration.clientId();
+
+ progress.update(75, "Creating encrypted machine assertion");
+ String assertion = assertionService.generate(
+ clientId,
+ request.installationCode().trim(),
+ settings.cloudServiceUrl() + profile.tokenPath(),
+ keys,
+ profile);
+
+ progress.update(88, "Writing on-premises deployment files");
+ Path output = deploymentWriter.write(
+ request.outputDirectory().toAbsolutePath().normalize(),
+ installationUuid,
+ request.installationCode().trim(),
+ clientId,
+ validation,
+ registration,
+ keys,
+ assertion,
+ settings,
+ profile,
+ request.dockerImage().trim(),
+ request.optionalFields());
+ progress.update(100, "Installation package created successfully");
+ return new InstallationResult(
+ registration.installationId(),
+ request.installationCode().trim(),
+ clientId,
+ output);
+ }
+
+ private void validate(InstallationRequest request) {
+ if (request == null) {
+ throw new IllegalArgumentException("Installation request is required");
+ }
+ required(request.clientCode(), "Client code");
+ required(request.licenseKey(), "License key");
+ required(request.installationCode(), "Installation code");
+ required(request.installationName(), "Installation name");
+ required(request.dockerImage(), "Docker image");
+ if (!request.dockerImage().matches(
+ "[A-Za-z0-9][A-Za-z0-9._:/@-]{0,254}")) {
+ throw new IllegalArgumentException(
+ "Docker image contains invalid characters");
+ }
+ if (request.outputDirectory() == null) {
+ throw new IllegalArgumentException("Output directory is required");
+ }
+ }
+
+ private void required(String value, String label) {
+ if (value == null || value.isBlank()) {
+ throw new IllegalArgumentException(label + " is required");
+ }
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallationWizard.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationWizard.java
index aedf34b..5074fb2 100644
--- a/cygnus-installer/src/main/java/com/cygnus/installer/InstallationWizard.java
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallationWizard.java
@@ -2,35 +2,31 @@ package com.cygnus.installer;
import java.io.Console;
import java.nio.file.Path;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.Scanner;
-import java.util.UUID;
import org.springframework.stereotype.Service;
@Service
public class InstallationWizard {
- private final DockerPrerequisiteChecker prerequisites;
- private final ActivationClient activationClient;
- private final InstallationKeyService keyService;
- private final DeploymentWriter deploymentWriter;
- private final InstallerProperties properties;
+ private final InstallationService installationService;
+ private final InstallerSettings settings;
+ private final ProductProfile profile;
public InstallationWizard(
- DockerPrerequisiteChecker prerequisites,
- ActivationClient activationClient,
- InstallationKeyService keyService,
- DeploymentWriter deploymentWriter,
- InstallerProperties properties) {
- this.prerequisites = prerequisites;
- this.activationClient = activationClient;
- this.keyService = keyService;
- this.deploymentWriter = deploymentWriter;
- this.properties = properties;
+ InstallationService installationService,
+ InstallerSettings settings,
+ ProductProfile profile) {
+ this.installationService = installationService;
+ this.settings = settings;
+ this.profile = profile;
}
public void run() {
- System.out.println("Cygnus installation wizard");
- prerequisites.verify();
+ System.out.println("Technobee Service Installer");
+ System.out.println("Selected product: " + profile.displayName());
+ installationService.verifyPrerequisites();
System.out.println("Docker prerequisites: OK");
Console console = System.console();
@@ -39,34 +35,44 @@ public class InstallationWizard {
String licenseKey = secret(console, scanner, "License key");
String installationCode = prompt(console, scanner, "Installation code");
String installationName = prompt(console, scanner, "Installation name");
- String environment = prompt(console, scanner, "Environment (prod/uat/dev)");
+ String dockerImage = prompt(
+ console,
+ scanner,
+ profile.displayName() + " Docker image");
+ Map optionalFields = promptOptionalFields(console, scanner);
String outputDirectory = promptWithDefault(
console,
scanner,
"Output directory",
- properties.outputDirectory());
+ settings.defaultOutputDirectory().toString());
- UUID installationUuid = UUID.randomUUID();
- var validation = activationClient.validate(
- clientCode, licenseKey, installationUuid, properties.version());
- var keys = keyService.generate();
- var registration = activationClient.register(
- validation,
+ InstallationResult result = installationService.install(
+ new InstallationRequest(
+ clientCode,
+ licenseKey,
installationCode,
installationName,
- keys.publicKeyPem(),
- properties.version(),
- environment);
- Path output = deploymentWriter.write(
+ dockerImage,
Path.of(outputDirectory).toAbsolutePath().normalize(),
- installationUuid,
- installationCode,
- validation,
- registration,
- keys,
- properties.cloudUrl());
- System.out.println("Installation registered: " + registration.installationId());
- System.out.println("Deployment files created at: " + output);
+ optionalFields),
+ (percentage, message) ->
+ System.out.println("[" + percentage + "%] " + message));
+ System.out.println("Installation registered: " + result.installationId());
+ System.out.println("Deployment files created at: " + result.outputDirectory());
+ }
+
+ private Map promptOptionalFields(
+ Console console, Scanner scanner) {
+ Map values = new LinkedHashMap<>();
+ for (String field : profile.optionalInstallationFields()) {
+ values.put(field, prompt(console, scanner, displayLabel(field)));
+ }
+ return values;
+ }
+
+ private String displayLabel(String field) {
+ String words = field.replace('_', ' ').replace('-', ' ');
+ return Character.toUpperCase(words.charAt(0)) + words.substring(1);
}
private String prompt(Console console, Scanner scanner, String label) {
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallerBootstrapProperties.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerBootstrapProperties.java
new file mode 100644
index 0000000..212b5eb
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerBootstrapProperties.java
@@ -0,0 +1,6 @@
+package com.cygnus.installer;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "technobee.installer")
+public record InstallerBootstrapProperties(String config, String version) {}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfiguration.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfiguration.java
index 5274e81..c146f90 100644
--- a/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfiguration.java
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfiguration.java
@@ -1,16 +1,35 @@
package com.cygnus.installer;
+import java.nio.file.Path;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
-@EnableConfigurationProperties(InstallerProperties.class)
+@EnableConfigurationProperties(InstallerBootstrapProperties.class)
public class InstallerConfiguration {
@Bean
- WebClient installerWebClient(InstallerProperties properties) {
- return WebClient.builder().baseUrl(properties.cloudUrl()).build();
+ InstallerSettings installerSettings(
+ InstallerBootstrapProperties bootstrap,
+ IniConfigurationLoader loader) {
+ return loader.load(
+ Path.of(bootstrap.config()).toAbsolutePath().normalize(),
+ bootstrap.version());
+ }
+
+ @Bean
+ ProductProfile productProfile(
+ InstallerSettings settings,
+ ProductProfileRegistry registry) {
+ return registry.resolve(settings);
+ }
+
+ @Bean
+ WebClient installerWebClient(InstallerSettings settings) {
+ return WebClient.builder()
+ .baseUrl(settings.cloudServiceUrl().toString())
+ .build();
}
}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfigurationException.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfigurationException.java
new file mode 100644
index 0000000..3b96f5f
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfigurationException.java
@@ -0,0 +1,11 @@
+package com.cygnus.installer;
+
+public class InstallerConfigurationException extends RuntimeException {
+ public InstallerConfigurationException(String message) {
+ super(message);
+ }
+
+ public InstallerConfigurationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallerProperties.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerProperties.java
deleted file mode 100644
index d95cb5f..0000000
--- a/cygnus-installer/src/main/java/com/cygnus/installer/InstallerProperties.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.cygnus.installer;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-@ConfigurationProperties(prefix = "cygnus.installer")
-public record InstallerProperties(
- String cloudUrl,
- String outputDirectory,
- String version) {}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/InstallerSettings.java b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerSettings.java
new file mode 100644
index 0000000..daaccce
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/InstallerSettings.java
@@ -0,0 +1,23 @@
+package com.cygnus.installer;
+
+import java.net.URI;
+import java.nio.file.Path;
+
+public record InstallerSettings(
+ String product,
+ URI cloudServiceUrl,
+ String installerApiBasePath,
+ String environment,
+ Path defaultOutputDirectory,
+ Path configurationDirectory,
+ String installerVersion,
+ IniDocument ini) {
+
+ public String validationPath() {
+ return installerApiBasePath + "/activation/validate";
+ }
+
+ public String registrationPath() {
+ return installerApiBasePath + "/register";
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/MachineAssertionService.java b/cygnus-installer/src/main/java/com/cygnus/installer/MachineAssertionService.java
new file mode 100644
index 0000000..4120fc7
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/MachineAssertionService.java
@@ -0,0 +1,81 @@
+package com.cygnus.installer;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.JWEHeader;
+import com.nimbusds.jose.JWEObject;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.crypto.RSAEncrypter;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.security.KeyFactory;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Base64;
+import java.util.Date;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MachineAssertionService {
+
+ public String generate(
+ String clientId,
+ String installationCode,
+ String tokenAudience,
+ InstallationKeyPair installationKeys,
+ ProductProfile profile) {
+ try {
+ Instant issuedAt = Instant.now();
+ JWTClaimsSet claims = new JWTClaimsSet.Builder()
+ .issuer(clientId)
+ .subject(clientId)
+ .audience(tokenAudience)
+ .issueTime(Date.from(issuedAt))
+ .expirationTime(Date.from(issuedAt.plus(365, ChronoUnit.DAYS)))
+ .claim("installation_id", installationCode)
+ .build();
+ SignedJWT signed = new SignedJWT(
+ new JWSHeader(JWSAlgorithm.RS256), claims);
+ signed.sign(new RSASSASigner(privateKey(installationKeys.privateKeyPem())));
+
+ JWEObject encrypted = new JWEObject(
+ new JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM),
+ new Payload(signed.serialize()));
+ encrypted.encrypt(new RSAEncrypter(publicKey(
+ Files.readString(
+ profile.assertionEncryptionPublicKey(),
+ StandardCharsets.US_ASCII))));
+ return encrypted.serialize();
+ } catch (Exception exception) {
+ throw new IllegalStateException(
+ "Could not generate the local machine assertion", exception);
+ }
+ }
+
+ private RSAPrivateKey privateKey(String pem) throws Exception {
+ return (RSAPrivateKey) KeyFactory.getInstance("RSA")
+ .generatePrivate(new PKCS8EncodedKeySpec(
+ Base64.getDecoder().decode(pem(pem, "PRIVATE KEY"))));
+ }
+
+ private RSAPublicKey publicKey(String pem) throws Exception {
+ return (RSAPublicKey) KeyFactory.getInstance("RSA")
+ .generatePublic(new X509EncodedKeySpec(
+ Base64.getDecoder().decode(pem(pem, "PUBLIC KEY"))));
+ }
+
+ private String pem(String value, String type) {
+ return value.replace("-----BEGIN " + type + "-----", "")
+ .replace("-----END " + type + "-----", "")
+ .replaceAll("\\s", "");
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfile.java b/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfile.java
new file mode 100644
index 0000000..ab81cc4
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfile.java
@@ -0,0 +1,17 @@
+package com.cygnus.installer;
+
+import java.nio.file.Path;
+import java.util.List;
+
+public record ProductProfile(
+ String product,
+ String displayName,
+ String serviceName,
+ String imageEnvironmentVariable,
+ String configurationRoot,
+ String configurationFileName,
+ String installationConfigEnvironmentVariable,
+ String containerConfigurationPath,
+ String tokenPath,
+ Path assertionEncryptionPublicKey,
+ List optionalInstallationFields) {}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfileRegistry.java b/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfileRegistry.java
new file mode 100644
index 0000000..1bbe615
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfileRegistry.java
@@ -0,0 +1,97 @@
+package com.cygnus.installer;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ProductProfileRegistry {
+
+ public ProductProfile resolve(InstallerSettings settings) {
+ String section = "profile." + settings.product();
+ IniDocument ini = settings.ini();
+ Path publicKey = resolvePath(
+ settings.configurationDirectory(),
+ ini.required(section, "assertion_encryption_public_key"));
+ if (!Files.isRegularFile(publicKey)) {
+ throw new InstallerConfigurationException(
+ "Assertion encryption public key was not found: " + publicKey);
+ }
+ return new ProductProfile(
+ settings.product(),
+ ini.required(section, "display_name"),
+ safeIdentifier(
+ ini.required(section, "service_name"),
+ "service_name"),
+ safeIdentifier(
+ ini.required(section, "image_environment_variable"),
+ "image_environment_variable"),
+ safeIdentifier(
+ ini.required(section, "configuration_root"),
+ "configuration_root"),
+ safeFileName(
+ ini.required(section, "configuration_file_name"),
+ "configuration_file_name"),
+ safeIdentifier(
+ ini.required(
+ section,
+ "installation_config_environment_variable"),
+ "installation_config_environment_variable"),
+ absoluteContainerPath(
+ ini.required(section, "container_configuration_path")),
+ absoluteApiPath(ini.required(section, "token_path")),
+ publicKey,
+ commaSeparated(ini.optional(section, "optional_fields", "")));
+ }
+
+ private String safeIdentifier(String value, String setting) {
+ if (!value.matches("[A-Za-z][A-Za-z0-9_-]*")) {
+ throw new InstallerConfigurationException(setting + " contains invalid characters");
+ }
+ return value;
+ }
+
+ private String safeFileName(String value, String setting) {
+ if (!value.matches("[A-Za-z0-9][A-Za-z0-9._-]*")) {
+ throw new InstallerConfigurationException(setting + " must be a safe file name");
+ }
+ return value;
+ }
+
+ private String absoluteContainerPath(String value) {
+ if (!value.startsWith("/") || value.contains("..")) {
+ throw new InstallerConfigurationException(
+ "container_configuration_path must be an absolute safe path");
+ }
+ return value;
+ }
+
+ private String absoluteApiPath(String value) {
+ if (!value.startsWith("/") || value.contains("..")) {
+ throw new InstallerConfigurationException(
+ "token_path must be an absolute API path");
+ }
+ return value;
+ }
+
+ private List commaSeparated(String value) {
+ if (value.isBlank()) {
+ return List.of();
+ }
+ return Arrays.stream(value.split(","))
+ .map(String::trim)
+ .map(field -> safeIdentifier(
+ field.toLowerCase(Locale.ROOT), "optional_fields"))
+ .toList();
+ }
+
+ private Path resolvePath(Path directory, String value) {
+ Path path = Path.of(value);
+ return (path.isAbsolute() ? path : directory.resolve(path))
+ .toAbsolutePath()
+ .normalize();
+ }
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/SwingInstallationWizard.java b/cygnus-installer/src/main/java/com/cygnus/installer/SwingInstallationWizard.java
new file mode 100644
index 0000000..0f2af2c
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/SwingInstallationWizard.java
@@ -0,0 +1,515 @@
+package com.cygnus.installer;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
+import javax.swing.UIManager;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SwingInstallationWizard {
+
+ private static final String WELCOME = "welcome";
+ private static final String DETAILS = "details";
+ private static final String INSTALLING = "installing";
+ private static final Color ACCENT = new Color(35, 97, 146);
+ private static final Color BACKGROUND = new Color(236, 243, 247);
+ private static final Color PANEL = new Color(249, 251, 252);
+
+ private final InstallationService installationService;
+ private final InstallerSettings settings;
+ private final ProductProfile profile;
+ private final CountDownLatch closed = new CountDownLatch(1);
+
+ private JFrame frame;
+ private CardLayout cards;
+ private JPanel cardPanel;
+ private JTextField clientCode;
+ private JPasswordField licenseKey;
+ private JTextField installationCode;
+ private JTextField installationName;
+ private JTextField dockerImage;
+ private JTextField outputDirectory;
+ private final Map optionalFields = new LinkedHashMap<>();
+ private JProgressBar progressBar;
+ private JLabel progressMessage;
+ private JTextArea resultText;
+ private JButton closeButton;
+
+ public SwingInstallationWizard(
+ InstallationService installationService,
+ InstallerSettings settings,
+ ProductProfile profile) {
+ this.installationService = installationService;
+ this.settings = settings;
+ this.profile = profile;
+ }
+
+ public void launchAndWait() {
+ configureLookAndFeel();
+ try {
+ SwingUtilities.invokeAndWait(this::createAndShow);
+ closed.await();
+ } catch (InterruptedException exception) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Installer was interrupted", exception);
+ } catch (Exception exception) {
+ throw new IllegalStateException("Could not start installer window", exception);
+ }
+ }
+
+ private void configureLookAndFeel() {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception ignored) {
+ // The cross-platform Swing look and feel remains available.
+ }
+ }
+
+ private void createAndShow() {
+ frame = new JFrame("Technobee Service Installer");
+ frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ frame.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent event) {
+ close();
+ }
+ });
+ frame.setMinimumSize(new Dimension(720, 540));
+ frame.setSize(760, 590);
+ frame.setLocationRelativeTo(null);
+ frame.setContentPane(rootPanel());
+ frame.setVisible(true);
+ }
+
+ private JPanel rootPanel() {
+ JPanel root = new JPanel(new BorderLayout());
+ root.setBackground(BACKGROUND);
+ root.add(header(), BorderLayout.NORTH);
+ cards = new CardLayout();
+ cardPanel = new JPanel(cards);
+ cardPanel.setBackground(BACKGROUND);
+ cardPanel.add(welcomePanel(), WELCOME);
+ cardPanel.add(detailsPanel(), DETAILS);
+ cardPanel.add(installingPanel(), INSTALLING);
+ root.add(cardPanel, BorderLayout.CENTER);
+ return root;
+ }
+
+ private JPanel header() {
+ JPanel header = new JPanel();
+ header.setBackground(ACCENT);
+ header.setBorder(BorderFactory.createEmptyBorder(18, 24, 18, 24));
+ header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS));
+ JLabel title = new JLabel("Technobee Service Installer");
+ title.setForeground(Color.WHITE);
+ title.setFont(title.getFont().deriveFont(Font.BOLD, 22f));
+ JLabel product = new JLabel(profile.displayName() + " installation");
+ product.setForeground(new Color(220, 235, 246));
+ product.setFont(product.getFont().deriveFont(13f));
+ header.add(title);
+ header.add(Box.createVerticalStrut(4));
+ header.add(product);
+ return header;
+ }
+
+ private JPanel welcomePanel() {
+ JPanel panel = contentPanel();
+ panel.setLayout(new BorderLayout(0, 18));
+ JPanel copy = new JPanel();
+ copy.setOpaque(false);
+ copy.setLayout(new BoxLayout(copy, BoxLayout.Y_AXIS));
+ copy.add(heading("Welcome"));
+ copy.add(Box.createVerticalStrut(10));
+ copy.add(text("This wizard validates your license, registers this server, "
+ + "and creates the protected on-premises deployment package."));
+ copy.add(Box.createVerticalStrut(22));
+ copy.add(summaryRow("Product", profile.displayName()));
+ copy.add(summaryRow("Cloud service", settings.cloudServiceUrl().toString()));
+ copy.add(summaryRow("Environment", settings.environment()));
+ copy.add(summaryRow("Configuration", settings.configurationDirectory().toString()));
+ panel.add(copy, BorderLayout.CENTER);
+
+ JButton continueButton = primaryButton("Check Docker and continue");
+ continueButton.addActionListener(event -> checkPrerequisites(continueButton));
+ JPanel actions = actions(null, continueButton);
+ panel.add(actions, BorderLayout.SOUTH);
+ return panel;
+ }
+
+ private JPanel detailsPanel() {
+ JPanel panel = contentPanel();
+ panel.setLayout(new BorderLayout(0, 12));
+ JPanel top = new JPanel(new BorderLayout());
+ top.setOpaque(false);
+ top.add(heading("Installation details"), BorderLayout.NORTH);
+ top.add(text("Enter the activation details supplied by Technobee."), BorderLayout.SOUTH);
+ panel.add(top, BorderLayout.NORTH);
+
+ JPanel form = new JPanel(new GridBagLayout());
+ form.setBackground(PANEL);
+ form.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createLineBorder(new Color(205, 217, 225)),
+ BorderFactory.createEmptyBorder(14, 16, 14, 16)));
+ clientCode = new JTextField();
+ licenseKey = new JPasswordField();
+ installationCode = new JTextField();
+ installationName = new JTextField();
+ dockerImage = new JTextField();
+ outputDirectory = new JTextField(
+ settings.defaultOutputDirectory().toAbsolutePath().normalize().toString());
+ int row = 0;
+ row = addField(form, row, "Client code", clientCode, null);
+ row = addField(form, row, "License key", licenseKey, null);
+ row = addField(form, row, "Installation code", installationCode, null);
+ row = addField(form, row, "Installation name", installationName, null);
+ row = addField(
+ form,
+ row,
+ profile.displayName() + " Docker image",
+ dockerImage,
+ null);
+ for (String field : profile.optionalInstallationFields()) {
+ JTextField input = new JTextField();
+ optionalFields.put(field, input);
+ row = addField(form, row, displayLabel(field), input, null);
+ }
+ JButton browse = secondaryButton("Browse…");
+ browse.addActionListener(event -> chooseOutputDirectory());
+ addField(form, row, "Output directory", outputDirectory, browse);
+
+ JScrollPane scroll = new JScrollPane(form);
+ scroll.setBorder(BorderFactory.createEmptyBorder());
+ scroll.getVerticalScrollBar().setUnitIncrement(12);
+ panel.add(scroll, BorderLayout.CENTER);
+
+ JButton back = secondaryButton("Back");
+ back.addActionListener(event -> cards.show(cardPanel, WELCOME));
+ JButton install = primaryButton("Install");
+ install.addActionListener(event -> startInstallation());
+ panel.add(actions(back, install), BorderLayout.SOUTH);
+ return panel;
+ }
+
+ private JPanel installingPanel() {
+ JPanel panel = contentPanel();
+ panel.setLayout(new BorderLayout(0, 18));
+ JPanel center = new JPanel();
+ center.setOpaque(false);
+ center.setLayout(new BoxLayout(center, BoxLayout.Y_AXIS));
+ center.add(heading("Installing " + profile.displayName()));
+ center.add(Box.createVerticalStrut(20));
+ progressBar = new JProgressBar(0, 100);
+ progressBar.setStringPainted(true);
+ progressBar.setAlignmentX(Component.LEFT_ALIGNMENT);
+ progressBar.setMaximumSize(new Dimension(Integer.MAX_VALUE, 28));
+ center.add(progressBar);
+ center.add(Box.createVerticalStrut(10));
+ progressMessage = text("Preparing installation");
+ center.add(progressMessage);
+ center.add(Box.createVerticalStrut(20));
+ resultText = new JTextArea(7, 40);
+ resultText.setEditable(false);
+ resultText.setLineWrap(true);
+ resultText.setWrapStyleWord(true);
+ resultText.setBackground(PANEL);
+ resultText.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+ resultText.setVisible(false);
+ center.add(resultText);
+ panel.add(center, BorderLayout.CENTER);
+
+ closeButton = primaryButton("Close");
+ closeButton.setEnabled(false);
+ closeButton.addActionListener(event -> close());
+ panel.add(actions(null, closeButton), BorderLayout.SOUTH);
+ return panel;
+ }
+
+ private void checkPrerequisites(JButton button) {
+ button.setEnabled(false);
+ button.setText("Checking Docker…");
+ new SwingWorker() {
+ @Override
+ protected Void doInBackground() {
+ installationService.verifyPrerequisites();
+ return null;
+ }
+
+ @Override
+ protected void done() {
+ button.setEnabled(true);
+ button.setText("Check Docker and continue");
+ try {
+ get();
+ cards.show(cardPanel, DETAILS);
+ clientCode.requestFocusInWindow();
+ } catch (Exception exception) {
+ showError(message(exception));
+ }
+ }
+ }.execute();
+ }
+
+ private void startInstallation() {
+ char[] secret = licenseKey.getPassword();
+ InstallationRequest request;
+ try {
+ request = new InstallationRequest(
+ clientCode.getText(),
+ new String(secret),
+ installationCode.getText(),
+ installationName.getText(),
+ dockerImage.getText(),
+ Path.of(outputDirectory.getText().trim()),
+ optionalValues());
+ validateForm(request);
+ } catch (Exception exception) {
+ Arrays.fill(secret, '\0');
+ showError(exception.getMessage());
+ return;
+ }
+ Arrays.fill(secret, '\0');
+ cards.show(cardPanel, INSTALLING);
+ closeButton.setEnabled(false);
+ resultText.setVisible(false);
+
+ new SwingWorker() {
+ @Override
+ protected InstallationResult doInBackground() {
+ return installationService.install(
+ request,
+ (percentage, message) ->
+ publish(new ProgressUpdate(percentage, message)));
+ }
+
+ @Override
+ protected void process(java.util.List updates) {
+ ProgressUpdate update = updates.getLast();
+ progressBar.setValue(update.percentage());
+ progressMessage.setText(update.message());
+ }
+
+ @Override
+ protected void done() {
+ closeButton.setEnabled(true);
+ try {
+ InstallationResult result = get();
+ progressBar.setValue(100);
+ progressMessage.setText("Installation completed");
+ resultText.setText(
+ "Installation ID: " + result.installationId()
+ + "\nClient ID: " + result.clientId()
+ + "\nOutput directory: " + result.outputDirectory()
+ + "\n\nKeep the private key and machine assertion secure.");
+ resultText.setVisible(true);
+ resultText.revalidate();
+ } catch (Exception exception) {
+ progressMessage.setText("Installation failed");
+ progressBar.setValue(0);
+ resultText.setText(message(exception));
+ resultText.setForeground(new Color(160, 35, 35));
+ resultText.setVisible(true);
+ resultText.revalidate();
+ }
+ }
+ }.execute();
+ }
+
+ private void validateForm(InstallationRequest request) {
+ if (request.clientCode().isBlank()) {
+ throw new IllegalArgumentException("Client code is required.");
+ }
+ if (request.licenseKey().isBlank()) {
+ throw new IllegalArgumentException("License key is required.");
+ }
+ if (request.installationCode().isBlank()) {
+ throw new IllegalArgumentException("Installation code is required.");
+ }
+ if (request.installationName().isBlank()) {
+ throw new IllegalArgumentException("Installation name is required.");
+ }
+ if (request.dockerImage().isBlank()) {
+ throw new IllegalArgumentException("Docker image is required.");
+ }
+ if (outputDirectory.getText().isBlank()) {
+ throw new IllegalArgumentException("Output directory is required.");
+ }
+ }
+
+ private Map optionalValues() {
+ Map values = new LinkedHashMap<>();
+ optionalFields.forEach((name, input) -> values.put(name, input.getText().trim()));
+ return values;
+ }
+
+ private void chooseOutputDirectory() {
+ JFileChooser chooser = new JFileChooser(outputDirectory.getText());
+ chooser.setDialogTitle("Select installation output directory");
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ if (chooser.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION) {
+ outputDirectory.setText(chooser.getSelectedFile().toPath()
+ .toAbsolutePath().normalize().toString());
+ }
+ }
+
+ private int addField(
+ JPanel form,
+ int row,
+ String label,
+ JTextField input,
+ JButton accessory) {
+ GridBagConstraints labelConstraints = constraints(0, row);
+ labelConstraints.weightx = 0;
+ labelConstraints.fill = GridBagConstraints.NONE;
+ labelConstraints.anchor = GridBagConstraints.LINE_START;
+ JLabel fieldLabel = new JLabel(label);
+ fieldLabel.setFont(fieldLabel.getFont().deriveFont(Font.BOLD, 12f));
+ form.add(fieldLabel, labelConstraints);
+
+ GridBagConstraints inputConstraints = constraints(1, row);
+ inputConstraints.weightx = 1;
+ inputConstraints.fill = GridBagConstraints.HORIZONTAL;
+ input.setPreferredSize(new Dimension(360, 29));
+ form.add(input, inputConstraints);
+ if (accessory != null) {
+ GridBagConstraints buttonConstraints = constraints(2, row);
+ buttonConstraints.weightx = 0;
+ buttonConstraints.fill = GridBagConstraints.NONE;
+ form.add(accessory, buttonConstraints);
+ }
+ return row + 1;
+ }
+
+ private GridBagConstraints constraints(int column, int row) {
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.gridx = column;
+ constraints.gridy = row;
+ constraints.insets = new Insets(6, column == 0 ? 0 : 12, 6, 0);
+ return constraints;
+ }
+
+ private JPanel contentPanel() {
+ JPanel panel = new JPanel();
+ panel.setBackground(BACKGROUND);
+ panel.setBorder(BorderFactory.createEmptyBorder(24, 30, 22, 30));
+ return panel;
+ }
+
+ private JPanel actions(JButton left, JButton right) {
+ JPanel actions = new JPanel(new BorderLayout());
+ actions.setOpaque(false);
+ actions.setBorder(BorderFactory.createCompoundBorder(
+ new JSeparator().getBorder(),
+ BorderFactory.createEmptyBorder(14, 0, 0, 0)));
+ if (left != null) {
+ actions.add(left, BorderLayout.WEST);
+ }
+ actions.add(right, BorderLayout.EAST);
+ return actions;
+ }
+
+ private JLabel heading(String value) {
+ JLabel label = new JLabel(value);
+ label.setFont(label.getFont().deriveFont(Font.BOLD, 19f));
+ label.setForeground(new Color(35, 48, 58));
+ return label;
+ }
+
+ private JLabel text(String value) {
+ JLabel label = new JLabel("" + value + "");
+ label.setForeground(new Color(75, 88, 99));
+ label.setAlignmentX(Component.LEFT_ALIGNMENT);
+ return label;
+ }
+
+ private JPanel summaryRow(String label, String value) {
+ JPanel row = new JPanel(new BorderLayout(18, 0));
+ row.setOpaque(false);
+ row.setBorder(BorderFactory.createEmptyBorder(7, 0, 7, 0));
+ JLabel name = new JLabel(label);
+ name.setPreferredSize(new Dimension(130, 20));
+ name.setFont(name.getFont().deriveFont(Font.BOLD));
+ row.add(name, BorderLayout.WEST);
+ row.add(new JLabel(value), BorderLayout.CENTER);
+ row.setMaximumSize(new Dimension(Integer.MAX_VALUE, 36));
+ return row;
+ }
+
+ private JButton primaryButton(String text) {
+ JButton button = new JButton(text);
+ button.setBackground(ACCENT);
+ button.setForeground(Color.WHITE);
+ button.setOpaque(true);
+ button.setBorder(BorderFactory.createEmptyBorder(8, 18, 8, 18));
+ return button;
+ }
+
+ private JButton secondaryButton(String text) {
+ JButton button = new JButton(text);
+ button.setBorder(BorderFactory.createEmptyBorder(8, 18, 8, 18));
+ return button;
+ }
+
+ private String displayLabel(String field) {
+ String words = field.replace('_', ' ').replace('-', ' ');
+ return Character.toUpperCase(words.charAt(0)) + words.substring(1);
+ }
+
+ private void showError(String message) {
+ JOptionPane.showMessageDialog(
+ frame,
+ message,
+ "Technobee Service Installer",
+ JOptionPane.ERROR_MESSAGE);
+ }
+
+ private String message(Throwable throwable) {
+ Throwable current = throwable;
+ while (current.getCause() != null) {
+ current = current.getCause();
+ }
+ return current.getMessage() == null
+ ? current.getClass().getSimpleName()
+ : current.getMessage();
+ }
+
+ private void close() {
+ if (frame != null) {
+ frame.dispose();
+ }
+ closed.countDown();
+ }
+
+ private record ProgressUpdate(int percentage, String message) {}
+}
diff --git a/cygnus-installer/src/main/java/com/cygnus/installer/TechnobeeServiceInstallerApplication.java b/cygnus-installer/src/main/java/com/cygnus/installer/TechnobeeServiceInstallerApplication.java
new file mode 100644
index 0000000..558e607
--- /dev/null
+++ b/cygnus-installer/src/main/java/com/cygnus/installer/TechnobeeServiceInstallerApplication.java
@@ -0,0 +1,68 @@
+package com.cygnus.installer;
+
+import java.awt.GraphicsEnvironment;
+import java.util.Arrays;
+import javax.swing.JOptionPane;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.WebApplicationType;
+import org.springframework.context.ConfigurableApplicationContext;
+
+@SpringBootApplication
+public class TechnobeeServiceInstallerApplication implements CommandLineRunner {
+
+ private final InstallationWizard wizard;
+ private final SwingInstallationWizard swingWizard;
+
+ public TechnobeeServiceInstallerApplication(
+ InstallationWizard wizard,
+ SwingInstallationWizard swingWizard) {
+ this.wizard = wizard;
+ this.swingWizard = swingWizard;
+ }
+
+ public static void main(String[] args) {
+ SpringApplication application =
+ new SpringApplication(TechnobeeServiceInstallerApplication.class);
+ application.setWebApplicationType(WebApplicationType.NONE);
+ application.setLogStartupInfo(false);
+ try {
+ ConfigurableApplicationContext context = application.run(args);
+ System.exit(SpringApplication.exit(context));
+ } catch (Exception exception) {
+ showStartupError(exception, args);
+ System.exit(1);
+ }
+ }
+
+ @Override
+ public void run(String... args) {
+ boolean cli = Arrays.asList(args).contains("--cli");
+ if (cli || GraphicsEnvironment.isHeadless()) {
+ wizard.run();
+ return;
+ }
+ swingWizard.launchAndWait();
+ }
+
+ private static void showStartupError(Exception exception, String[] args) {
+ Throwable cause = exception;
+ while (cause.getCause() != null) {
+ cause = cause.getCause();
+ }
+ String message = cause.getMessage() == null
+ ? cause.getClass().getSimpleName()
+ : cause.getMessage();
+ if (!GraphicsEnvironment.isHeadless()
+ && !Arrays.asList(args).contains("--cli")) {
+ JOptionPane.showMessageDialog(
+ null,
+ message,
+ "Technobee Service Installer configuration error",
+ JOptionPane.ERROR_MESSAGE);
+ } else {
+ System.err.println("Technobee Service Installer: " + message);
+ }
+ }
+}
diff --git a/cygnus-installer/src/main/resources/application.yml b/cygnus-installer/src/main/resources/application.yml
index 47e863e..2dcf6bb 100644
--- a/cygnus-installer/src/main/resources/application.yml
+++ b/cygnus-installer/src/main/resources/application.yml
@@ -2,12 +2,11 @@ spring:
main:
banner-mode: "off"
application:
- name: cygnus-installer
-cygnus:
+ name: technobee-service-installer
+technobee:
installer:
- cloud-url: ${CYGNUS_CLOUD_URL:http://localhost:8090}
- output-directory: ${CYGNUS_INSTALL_OUTPUT:./cygnus-installation}
- version: ${CYGNUS_INSTALLER_VERSION:1.0.0}
+ config: ${TECHNOBEE_INSTALLER_CONFIG:./installer.ini}
+ version: ${TECHNOBEE_INSTALLER_VERSION:1.0.0}
logging:
level:
root: WARN
diff --git a/cygnus-installer/src/test/java/com/cygnus/installer/DeploymentWriterTest.java b/cygnus-installer/src/test/java/com/cygnus/installer/DeploymentWriterTest.java
new file mode 100644
index 0000000..7e148e1
--- /dev/null
+++ b/cygnus-installer/src/test/java/com/cygnus/installer/DeploymentWriterTest.java
@@ -0,0 +1,95 @@
+package com.cygnus.installer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.OffsetDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class DeploymentWriterTest {
+
+ @TempDir
+ Path temporaryDirectory;
+
+ @Test
+ void writesPortableProductDeploymentAndKeepsSecretsLocal() throws Exception {
+ UUID tenantId = UUID.randomUUID();
+ UUID installationId = UUID.randomUUID();
+ UUID installationUuid = UUID.randomUUID();
+ var validation = new ActivationDtos.ValidationResponse(
+ "activation-token",
+ OffsetDateTime.now().plusMinutes(5),
+ tenantId,
+ "matrix-client",
+ "FULL",
+ 2);
+ var registration = new ActivationDtos.RegistrationResponse(
+ installationId,
+ installationUuid,
+ tenantId,
+ null,
+ "primary",
+ 1,
+ "ACTIVE");
+ var profile = new ProductProfile(
+ "matrix",
+ "Matrix",
+ "matrix-onprem",
+ "MATRIX_IMAGE",
+ "matrix",
+ "installation.yml",
+ "MATRIX_INSTALLATION_CONFIG",
+ "/srv/matrix/config/installation.yml",
+ "/oauth2/token",
+ temporaryDirectory.resolve("unused.pem"),
+ List.of("region"));
+ var settings = new InstallerSettings(
+ "matrix",
+ URI.create("https://cloud.example.com"),
+ "/api/v1/installations",
+ "production",
+ temporaryDirectory,
+ temporaryDirectory,
+ "1",
+ new IniDocument(Map.of()));
+
+ Path output = new DeploymentWriter().write(
+ temporaryDirectory.resolve("output"),
+ installationUuid,
+ "primary",
+ "matrix-client",
+ validation,
+ registration,
+ new InstallationKeyService().generate(),
+ "encrypted.assertion.value",
+ settings,
+ profile,
+ "registry.example.com/matrix:1.0.0",
+ Map.of("region", "north"));
+
+ String config = Files.readString(output.resolve("config/installation.yml"));
+ String compose = Files.readString(output.resolve("compose.yml"));
+ assertThat(config)
+ .contains("client-id: \"matrix-client\"")
+ .contains("installation-id: \"" + installationId + "\"")
+ .contains("cloud-url: \"https://cloud.example.com\"")
+ .contains("region: \"north\"")
+ .doesNotContain("activation-token");
+ assertThat(compose)
+ .contains("matrix-onprem:")
+ .contains("./config:/srv/matrix/config:ro")
+ .contains("MATRIX_INSTALLATION_CONFIG");
+ assertThat(output.resolve(".env"))
+ .hasContent("MATRIX_IMAGE=registry.example.com/matrix:1.0.0\n");
+ assertThat(output.resolve("config/machine-assertion.jwt")).hasContent(
+ "encrypted.assertion.value");
+ assertThat(output.resolve("config/keys/client-signing-private.pem"))
+ .isRegularFile();
+ }
+}
diff --git a/cygnus-installer/src/test/java/com/cygnus/installer/DockerPrerequisiteCheckerTest.java b/cygnus-installer/src/test/java/com/cygnus/installer/DockerPrerequisiteCheckerTest.java
index 00b9613..0ebf1fb 100644
--- a/cygnus-installer/src/test/java/com/cygnus/installer/DockerPrerequisiteCheckerTest.java
+++ b/cygnus-installer/src/test/java/com/cygnus/installer/DockerPrerequisiteCheckerTest.java
@@ -2,9 +2,6 @@ package com.cygnus.installer;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import java.time.Duration;
import java.util.List;
@@ -14,19 +11,24 @@ class DockerPrerequisiteCheckerTest {
@Test
void blocksInstallationWhenDockerIsUnavailable() {
- CommandExecutor executor = mock(CommandExecutor.class);
- when(executor.execute(any(List.class), any(Duration.class)))
- .thenReturn(new CommandResult(127, "not found"));
+ CommandExecutor executor = executorReturning(new CommandResult(127, "not found"));
DockerPrerequisiteChecker checker = new DockerPrerequisiteChecker(executor);
assertThrows(PrerequisiteException.class, checker::verify);
}
@Test
void acceptsDockerEngineAndComposeV2() {
- CommandExecutor executor = mock(CommandExecutor.class);
- when(executor.execute(any(List.class), any(Duration.class)))
- .thenReturn(new CommandResult(0, "ok"));
+ CommandExecutor executor = executorReturning(new CommandResult(0, "ok"));
DockerPrerequisiteChecker checker = new DockerPrerequisiteChecker(executor);
assertDoesNotThrow(checker::verify);
}
+
+ private CommandExecutor executorReturning(CommandResult result) {
+ return new CommandExecutor() {
+ @Override
+ public CommandResult execute(List command, Duration timeout) {
+ return result;
+ }
+ };
+ }
}
diff --git a/cygnus-installer/src/test/java/com/cygnus/installer/IniConfigurationLoaderTest.java b/cygnus-installer/src/test/java/com/cygnus/installer/IniConfigurationLoaderTest.java
new file mode 100644
index 0000000..819fdbf
--- /dev/null
+++ b/cygnus-installer/src/test/java/com/cygnus/installer/IniConfigurationLoaderTest.java
@@ -0,0 +1,84 @@
+package com.cygnus.installer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class IniConfigurationLoaderTest {
+
+ @TempDir
+ Path temporaryDirectory;
+
+ private final IniConfigurationLoader loader = new IniConfigurationLoader();
+
+ @Test
+ void loadsAndNormalizesInstallerSettings() throws Exception {
+ Path ini = write("""
+ [installer]
+ product=matrix
+ cloud_service_url=https://cloud.example.com/
+ installer_api_base_path=/api/v1/installations/
+ environment=production
+ """);
+
+ InstallerSettings settings = loader.load(ini, "1.2.3");
+
+ assertThat(settings.product()).isEqualTo("matrix");
+ assertThat(settings.cloudServiceUrl().toString())
+ .isEqualTo("https://cloud.example.com");
+ assertThat(settings.validationPath())
+ .isEqualTo("/api/v1/installations/activation/validate");
+ assertThat(settings.registrationPath())
+ .isEqualTo("/api/v1/installations/register");
+ assertThat(settings.defaultOutputDirectory())
+ .isEqualTo(Path.of("./matrix-installation"));
+ }
+
+ @Test
+ void rejectsUnknownProduct() throws Exception {
+ Path ini = write("""
+ [installer]
+ product=unknown
+ cloud_service_url=https://cloud.example.com
+ installer_api_base_path=/api/v1/installations
+ environment=production
+ """);
+
+ assertThatThrownBy(() -> loader.load(ini, "1"))
+ .isInstanceOf(InstallerConfigurationException.class)
+ .hasMessageContaining("Unsupported product");
+ }
+
+ @Test
+ void rejectsInvalidCloudUrlAndApiPath() throws Exception {
+ Path invalidUrl = write("""
+ [installer]
+ product=cygnus
+ cloud_service_url=cloud.example.com
+ installer_api_base_path=/api/v1/installations
+ environment=production
+ """);
+ assertThatThrownBy(() -> loader.load(invalidUrl, "1"))
+ .hasMessageContaining("absolute http(s) URL");
+
+ Path invalidPath = write("""
+ [installer]
+ product=cygnus
+ cloud_service_url=https://cloud.example.com
+ installer_api_base_path=api/v1/installations
+ environment=production
+ """);
+ assertThatThrownBy(() -> loader.load(invalidPath, "1"))
+ .hasMessageContaining("absolute safe URL path");
+ }
+
+ private Path write(String content) throws Exception {
+ Path path = temporaryDirectory.resolve("installer-" + System.nanoTime() + ".ini");
+ Files.writeString(path, content);
+ return path;
+ }
+}
diff --git a/cygnus-installer/src/test/java/com/cygnus/installer/InstallationServiceTest.java b/cygnus-installer/src/test/java/com/cygnus/installer/InstallationServiceTest.java
new file mode 100644
index 0000000..14d7ab0
--- /dev/null
+++ b/cygnus-installer/src/test/java/com/cygnus/installer/InstallationServiceTest.java
@@ -0,0 +1,29 @@
+package com.cygnus.installer;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.nio.file.Path;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+class InstallationServiceTest {
+
+ @Test
+ void rejectsIncompleteRequestBeforeCallingInfrastructure() {
+ InstallationService service =
+ new InstallationService(null, null, null, null, null, null, null);
+
+ assertThatThrownBy(() -> service.install(
+ new InstallationRequest(
+ "",
+ "",
+ "",
+ "",
+ "",
+ Path.of("."),
+ Map.of()),
+ (percentage, message) -> {}))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Client code is required");
+ }
+}
diff --git a/cygnus-installer/src/test/java/com/cygnus/installer/MachineAssertionServiceTest.java b/cygnus-installer/src/test/java/com/cygnus/installer/MachineAssertionServiceTest.java
new file mode 100644
index 0000000..2a603cf
--- /dev/null
+++ b/cygnus-installer/src/test/java/com/cygnus/installer/MachineAssertionServiceTest.java
@@ -0,0 +1,56 @@
+package com.cygnus.installer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyPairGenerator;
+import java.util.Base64;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class MachineAssertionServiceTest {
+
+ @TempDir
+ Path temporaryDirectory;
+
+ @Test
+ void generatesEncryptedAssertionUsingOnlyCloudPublicKey() throws Exception {
+ var generator = KeyPairGenerator.getInstance("RSA");
+ generator.initialize(2048);
+ var cloudKeys = generator.generateKeyPair();
+ Path cloudPublicKey = temporaryDirectory.resolve("cloud-public.pem");
+ Files.writeString(cloudPublicKey, pem(
+ "PUBLIC KEY", cloudKeys.getPublic().getEncoded()));
+ ProductProfile profile = new ProductProfile(
+ "matrix",
+ "Matrix",
+ "matrix-onprem",
+ "MATRIX_IMAGE",
+ "matrix",
+ "installation.yml",
+ "MATRIX_INSTALLATION_CONFIG",
+ "/opt/matrix/config/installation.yml",
+ "/oauth2/token",
+ cloudPublicKey,
+ List.of());
+
+ String assertion = new MachineAssertionService().generate(
+ "matrix-client",
+ "primary",
+ "https://cloud.example.com/oauth2/token",
+ new InstallationKeyService().generate(),
+ profile);
+
+ assertThat(assertion.split("\\.")).hasSize(5);
+ assertThat(assertion).doesNotContain("matrix-client");
+ }
+
+ private String pem(String type, byte[] encoded) {
+ return "-----BEGIN " + type + "-----\n"
+ + Base64.getMimeEncoder(64, new byte[] {'\n'})
+ .encodeToString(encoded)
+ + "\n-----END " + type + "-----\n";
+ }
+}
diff --git a/cygnus-installer/src/test/java/com/cygnus/installer/ProductProfileRegistryTest.java b/cygnus-installer/src/test/java/com/cygnus/installer/ProductProfileRegistryTest.java
new file mode 100644
index 0000000..63998d8
--- /dev/null
+++ b/cygnus-installer/src/test/java/com/cygnus/installer/ProductProfileRegistryTest.java
@@ -0,0 +1,49 @@
+package com.cygnus.installer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class ProductProfileRegistryTest {
+
+ @TempDir
+ Path temporaryDirectory;
+
+ @Test
+ void appliesProductProfileOverridesWithoutInstallerBranching() throws Exception {
+ Path publicKey = temporaryDirectory.resolve("cloud.pem");
+ Files.writeString(publicKey, "test");
+ Path ini = temporaryDirectory.resolve("installer.ini");
+ Files.writeString(ini, """
+ [installer]
+ product=cygnus
+ cloud_service_url=https://cloud.example.com
+ installer_api_base_path=/api/v1/installations
+ environment=production
+
+ [profile.cygnus]
+ display_name=Cygnus
+ assertion_encryption_public_key=cloud.pem
+ service_name=custom-cygnus
+ image_environment_variable=CYGNUS_IMAGE
+ configuration_root=cygnus
+ configuration_file_name=installation.yml
+ installation_config_environment_variable=CYGNUS_INSTALLATION_CONFIG
+ container_configuration_path=/opt/cygnus/config/installation.yml
+ token_path=/oauth2/token
+ optional_fields=region,site_code
+ """);
+
+ InstallerSettings settings = new IniConfigurationLoader().load(ini, "1");
+ ProductProfile profile = new ProductProfileRegistry().resolve(settings);
+
+ assertThat(profile.displayName()).isEqualTo("Cygnus");
+ assertThat(profile.serviceName()).isEqualTo("custom-cygnus");
+ assertThat(profile.optionalInstallationFields())
+ .containsExactly("region", "site_code");
+ assertThat(profile.assertionEncryptionPublicKey()).isEqualTo(publicKey);
+ }
+}
diff --git a/cygnus-installer/target/classes/application.yml b/cygnus-installer/target/classes/application.yml
index 47e863e..2dcf6bb 100644
--- a/cygnus-installer/target/classes/application.yml
+++ b/cygnus-installer/target/classes/application.yml
@@ -2,12 +2,11 @@ spring:
main:
banner-mode: "off"
application:
- name: cygnus-installer
-cygnus:
+ name: technobee-service-installer
+technobee:
installer:
- cloud-url: ${CYGNUS_CLOUD_URL:http://localhost:8090}
- output-directory: ${CYGNUS_INSTALL_OUTPUT:./cygnus-installation}
- version: ${CYGNUS_INSTALLER_VERSION:1.0.0}
+ config: ${TECHNOBEE_INSTALLER_CONFIG:./installer.ini}
+ version: ${TECHNOBEE_INSTALLER_VERSION:1.0.0}
logging:
level:
root: WARN
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/ActivationClient.class b/cygnus-installer/target/classes/com/cygnus/installer/ActivationClient.class
index b1a936a..45b583c 100644
Binary files a/cygnus-installer/target/classes/com/cygnus/installer/ActivationClient.class and b/cygnus-installer/target/classes/com/cygnus/installer/ActivationClient.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/ActivationDtos$RegistrationResponse.class b/cygnus-installer/target/classes/com/cygnus/installer/ActivationDtos$RegistrationResponse.class
index 288dcf3..7e0d541 100644
Binary files a/cygnus-installer/target/classes/com/cygnus/installer/ActivationDtos$RegistrationResponse.class and b/cygnus-installer/target/classes/com/cygnus/installer/ActivationDtos$RegistrationResponse.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/CygnusInstallerApplication.class b/cygnus-installer/target/classes/com/cygnus/installer/CygnusInstallerApplication.class
deleted file mode 100644
index 88f26d0..0000000
Binary files a/cygnus-installer/target/classes/com/cygnus/installer/CygnusInstallerApplication.class and /dev/null differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/DeploymentWriter.class b/cygnus-installer/target/classes/com/cygnus/installer/DeploymentWriter.class
index 5a7facb..49be4b1 100644
Binary files a/cygnus-installer/target/classes/com/cygnus/installer/DeploymentWriter.class and b/cygnus-installer/target/classes/com/cygnus/installer/DeploymentWriter.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/IniConfigurationLoader.class b/cygnus-installer/target/classes/com/cygnus/installer/IniConfigurationLoader.class
new file mode 100644
index 0000000..5bea7fa
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/IniConfigurationLoader.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/IniDocument.class b/cygnus-installer/target/classes/com/cygnus/installer/IniDocument.class
new file mode 100644
index 0000000..9955ec4
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/IniDocument.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallationProgressListener.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallationProgressListener.class
new file mode 100644
index 0000000..39ebaed
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/InstallationProgressListener.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallationRequest.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallationRequest.class
new file mode 100644
index 0000000..d0aa224
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/InstallationRequest.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallationResult.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallationResult.class
new file mode 100644
index 0000000..a817340
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/InstallationResult.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallationService.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallationService.class
new file mode 100644
index 0000000..749acc3
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/InstallationService.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallationWizard.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallationWizard.class
index c2a769a..42d4681 100644
Binary files a/cygnus-installer/target/classes/com/cygnus/installer/InstallationWizard.class and b/cygnus-installer/target/classes/com/cygnus/installer/InstallationWizard.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallerBootstrapProperties.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallerBootstrapProperties.class
new file mode 100644
index 0000000..468e3b5
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/InstallerBootstrapProperties.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallerConfiguration.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallerConfiguration.class
index 26e37cc..521d973 100644
Binary files a/cygnus-installer/target/classes/com/cygnus/installer/InstallerConfiguration.class and b/cygnus-installer/target/classes/com/cygnus/installer/InstallerConfiguration.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallerConfigurationException.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallerConfigurationException.class
new file mode 100644
index 0000000..53cd7c6
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/InstallerConfigurationException.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallerProperties.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallerProperties.class
deleted file mode 100644
index f596041..0000000
Binary files a/cygnus-installer/target/classes/com/cygnus/installer/InstallerProperties.class and /dev/null differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/InstallerSettings.class b/cygnus-installer/target/classes/com/cygnus/installer/InstallerSettings.class
new file mode 100644
index 0000000..72cbd80
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/InstallerSettings.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/MachineAssertionService.class b/cygnus-installer/target/classes/com/cygnus/installer/MachineAssertionService.class
new file mode 100644
index 0000000..4abd2e8
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/MachineAssertionService.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/ProductProfile.class b/cygnus-installer/target/classes/com/cygnus/installer/ProductProfile.class
new file mode 100644
index 0000000..e5c739a
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/ProductProfile.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/ProductProfileRegistry.class b/cygnus-installer/target/classes/com/cygnus/installer/ProductProfileRegistry.class
new file mode 100644
index 0000000..fc7e345
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/ProductProfileRegistry.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$1.class b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$1.class
new file mode 100644
index 0000000..02ab1f6
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$1.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$2.class b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$2.class
new file mode 100644
index 0000000..5fecbb4
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$2.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$3.class b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$3.class
new file mode 100644
index 0000000..16ffdf3
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$3.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$ProgressUpdate.class b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$ProgressUpdate.class
new file mode 100644
index 0000000..e150687
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard$ProgressUpdate.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard.class b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard.class
new file mode 100644
index 0000000..500682e
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/SwingInstallationWizard.class differ
diff --git a/cygnus-installer/target/classes/com/cygnus/installer/TechnobeeServiceInstallerApplication.class b/cygnus-installer/target/classes/com/cygnus/installer/TechnobeeServiceInstallerApplication.class
new file mode 100644
index 0000000..bd57d95
Binary files /dev/null and b/cygnus-installer/target/classes/com/cygnus/installer/TechnobeeServiceInstallerApplication.class differ
diff --git a/cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar.original b/cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar.original
deleted file mode 100644
index 21bdebf..0000000
Binary files a/cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar.original and /dev/null differ
diff --git a/cygnus-installer/target/maven-archiver/pom.properties b/cygnus-installer/target/maven-archiver/pom.properties
index 3f4c068..369a5c6 100644
--- a/cygnus-installer/target/maven-archiver/pom.properties
+++ b/cygnus-installer/target/maven-archiver/pom.properties
@@ -1,3 +1,3 @@
-artifactId=cygnus-installer
+artifactId=technobee-service-installer
groupId=com.cygnus
version=1.0.0-SNAPSHOT
diff --git a/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
index f0f707f..a7d895d 100644
--- a/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
+++ b/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -1,17 +1,33 @@
+com/cygnus/installer/MachineAssertionService.class
com/cygnus/installer/ActivationDtos$ValidationResponse.class
-com/cygnus/installer/ActivationDtos.class
-com/cygnus/installer/DockerPrerequisiteChecker.class
+com/cygnus/installer/SwingInstallationWizard$2.class
com/cygnus/installer/CommandResult.class
+com/cygnus/installer/InstallationProgressListener.class
+com/cygnus/installer/ProductProfileRegistry.class
+com/cygnus/installer/InstallationRequest.class
com/cygnus/installer/InstallerConfiguration.class
-com/cygnus/installer/CygnusInstallerApplication.class
+com/cygnus/installer/ProductProfile.class
com/cygnus/installer/InstallationWizard.class
-com/cygnus/installer/CommandExecutor.class
+com/cygnus/installer/TechnobeeServiceInstallerApplication.class
com/cygnus/installer/DeploymentWriter.class
-com/cygnus/installer/InstallerProperties.class
com/cygnus/installer/InstallationKeyService.class
com/cygnus/installer/ActivationClient.class
-com/cygnus/installer/ActivationDtos$RegistrationRequest.class
com/cygnus/installer/ActivationDtos$RegistrationResponse.class
+com/cygnus/installer/IniDocument.class
+com/cygnus/installer/SwingInstallationWizard$3.class
+com/cygnus/installer/InstallerConfigurationException.class
+com/cygnus/installer/SwingInstallationWizard.class
+com/cygnus/installer/ActivationDtos.class
+com/cygnus/installer/DockerPrerequisiteChecker.class
+com/cygnus/installer/InstallerBootstrapProperties.class
+com/cygnus/installer/SwingInstallationWizard$1.class
+com/cygnus/installer/CommandExecutor.class
+com/cygnus/installer/IniConfigurationLoader.class
+com/cygnus/installer/InstallationService.class
+com/cygnus/installer/InstallationResult.class
+com/cygnus/installer/ActivationDtos$RegistrationRequest.class
com/cygnus/installer/ActivationDtos$ValidationRequest.class
com/cygnus/installer/PrerequisiteException.class
+com/cygnus/installer/InstallerSettings.class
com/cygnus/installer/InstallationKeyPair.class
+com/cygnus/installer/SwingInstallationWizard$ProgressUpdate.class
diff --git a/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
index 3c5aa82..2c05edd 100644
--- a/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
+++ b/cygnus-installer/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -1,13 +1,25 @@
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ActivationClient.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ActivationDtos.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/CommandExecutor.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/CommandResult.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/CygnusInstallerApplication.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DeploymentWriter.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DockerPrerequisiteChecker.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationKeyPair.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationKeyService.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationWizard.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfiguration.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerProperties.java
-/Users/maddy/Projects/matrix/cygnus-installer/src/main/java/com/cygnus/installer/PrerequisiteException.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ActivationClient.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ActivationDtos.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/CommandExecutor.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/CommandResult.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DeploymentWriter.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/DockerPrerequisiteChecker.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/IniConfigurationLoader.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/IniDocument.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationKeyPair.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationKeyService.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationProgressListener.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationRequest.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationResult.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationService.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallationWizard.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerBootstrapProperties.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfiguration.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerConfigurationException.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/InstallerSettings.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/MachineAssertionService.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/PrerequisiteException.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfile.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/ProductProfileRegistry.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/SwingInstallationWizard.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/main/java/com/cygnus/installer/TechnobeeServiceInstallerApplication.java
diff --git a/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
index 4399feb..abfece7 100644
--- a/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
+++ b/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst
@@ -1 +1,7 @@
+com/cygnus/installer/MachineAssertionServiceTest.class
+com/cygnus/installer/InstallationServiceTest.class
+com/cygnus/installer/DockerPrerequisiteCheckerTest$1.class
+com/cygnus/installer/ProductProfileRegistryTest.class
+com/cygnus/installer/IniConfigurationLoaderTest.class
+com/cygnus/installer/DeploymentWriterTest.class
com/cygnus/installer/DockerPrerequisiteCheckerTest.class
diff --git a/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
index d6f5bc5..031c1c8 100644
--- a/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
+++ b/cygnus-installer/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst
@@ -1 +1,6 @@
-/Users/maddy/Projects/matrix/cygnus-installer/src/test/java/com/cygnus/installer/DockerPrerequisiteCheckerTest.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/DeploymentWriterTest.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/DockerPrerequisiteCheckerTest.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/IniConfigurationLoaderTest.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/InstallationServiceTest.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/MachineAssertionServiceTest.java
+/Users/maddy/Projects/cygnus/matrix/cygnus-installer/src/test/java/com/cygnus/installer/ProductProfileRegistryTest.java
diff --git a/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.DeploymentWriterTest.xml b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.DeploymentWriterTest.xml
new file mode 100644
index 0000000..bdb1e81
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.DeploymentWriterTest.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.DockerPrerequisiteCheckerTest.xml b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.DockerPrerequisiteCheckerTest.xml
index a01b3a9..93729c8 100644
--- a/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.DockerPrerequisiteCheckerTest.xml
+++ b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.DockerPrerequisiteCheckerTest.xml
@@ -1,9 +1,9 @@
-
+
-
+
@@ -13,10 +13,10 @@
-
+
-
+
@@ -24,13 +24,13 @@
-
+
-
+
@@ -46,7 +46,7 @@
-
+
@@ -59,13 +59,6 @@
-
-
-
-
+
+
\ No newline at end of file
diff --git a/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.IniConfigurationLoaderTest.xml b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.IniConfigurationLoaderTest.xml
new file mode 100644
index 0000000..119a621
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.IniConfigurationLoaderTest.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.InstallationServiceTest.xml b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.InstallationServiceTest.xml
new file mode 100644
index 0000000..d7e632b
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.InstallationServiceTest.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.MachineAssertionServiceTest.xml b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.MachineAssertionServiceTest.xml
new file mode 100644
index 0000000..50ac890
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.MachineAssertionServiceTest.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.ProductProfileRegistryTest.xml b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.ProductProfileRegistryTest.xml
new file mode 100644
index 0000000..fad70c1
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/TEST-com.cygnus.installer.ProductProfileRegistryTest.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cygnus-installer/target/surefire-reports/com.cygnus.installer.DeploymentWriterTest.txt b/cygnus-installer/target/surefire-reports/com.cygnus.installer.DeploymentWriterTest.txt
new file mode 100644
index 0000000..86dd065
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/com.cygnus.installer.DeploymentWriterTest.txt
@@ -0,0 +1,4 @@
+-------------------------------------------------------------------------------
+Test set: com.cygnus.installer.DeploymentWriterTest
+-------------------------------------------------------------------------------
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.206 s -- in com.cygnus.installer.DeploymentWriterTest
diff --git a/cygnus-installer/target/surefire-reports/com.cygnus.installer.DockerPrerequisiteCheckerTest.txt b/cygnus-installer/target/surefire-reports/com.cygnus.installer.DockerPrerequisiteCheckerTest.txt
index 7bd0538..7910fad 100644
--- a/cygnus-installer/target/surefire-reports/com.cygnus.installer.DockerPrerequisiteCheckerTest.txt
+++ b/cygnus-installer/target/surefire-reports/com.cygnus.installer.DockerPrerequisiteCheckerTest.txt
@@ -1,4 +1,4 @@
-------------------------------------------------------------------------------
Test set: com.cygnus.installer.DockerPrerequisiteCheckerTest
-------------------------------------------------------------------------------
-Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.412 s -- in com.cygnus.installer.DockerPrerequisiteCheckerTest
+Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 s -- in com.cygnus.installer.DockerPrerequisiteCheckerTest
diff --git a/cygnus-installer/target/surefire-reports/com.cygnus.installer.IniConfigurationLoaderTest.txt b/cygnus-installer/target/surefire-reports/com.cygnus.installer.IniConfigurationLoaderTest.txt
new file mode 100644
index 0000000..0ac4b17
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/com.cygnus.installer.IniConfigurationLoaderTest.txt
@@ -0,0 +1,4 @@
+-------------------------------------------------------------------------------
+Test set: com.cygnus.installer.IniConfigurationLoaderTest
+-------------------------------------------------------------------------------
+Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.006 s -- in com.cygnus.installer.IniConfigurationLoaderTest
diff --git a/cygnus-installer/target/surefire-reports/com.cygnus.installer.InstallationServiceTest.txt b/cygnus-installer/target/surefire-reports/com.cygnus.installer.InstallationServiceTest.txt
new file mode 100644
index 0000000..2191442
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/com.cygnus.installer.InstallationServiceTest.txt
@@ -0,0 +1,4 @@
+-------------------------------------------------------------------------------
+Test set: com.cygnus.installer.InstallationServiceTest
+-------------------------------------------------------------------------------
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 s -- in com.cygnus.installer.InstallationServiceTest
diff --git a/cygnus-installer/target/surefire-reports/com.cygnus.installer.MachineAssertionServiceTest.txt b/cygnus-installer/target/surefire-reports/com.cygnus.installer.MachineAssertionServiceTest.txt
new file mode 100644
index 0000000..ab82f75
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/com.cygnus.installer.MachineAssertionServiceTest.txt
@@ -0,0 +1,4 @@
+-------------------------------------------------------------------------------
+Test set: com.cygnus.installer.MachineAssertionServiceTest
+-------------------------------------------------------------------------------
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.301 s -- in com.cygnus.installer.MachineAssertionServiceTest
diff --git a/cygnus-installer/target/surefire-reports/com.cygnus.installer.ProductProfileRegistryTest.txt b/cygnus-installer/target/surefire-reports/com.cygnus.installer.ProductProfileRegistryTest.txt
new file mode 100644
index 0000000..e672b5e
--- /dev/null
+++ b/cygnus-installer/target/surefire-reports/com.cygnus.installer.ProductProfileRegistryTest.txt
@@ -0,0 +1,4 @@
+-------------------------------------------------------------------------------
+Test set: com.cygnus.installer.ProductProfileRegistryTest
+-------------------------------------------------------------------------------
+Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.010 s -- in com.cygnus.installer.ProductProfileRegistryTest
diff --git a/cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar b/cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar
similarity index 97%
rename from cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar
rename to cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar
index 0a0eae4..664659d 100644
Binary files a/cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar and b/cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar differ
diff --git a/cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar.original b/cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar.original
new file mode 100644
index 0000000..6f57db1
Binary files /dev/null and b/cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar.original differ
diff --git a/cygnus-installer/target/test-classes/com/cygnus/installer/DeploymentWriterTest.class b/cygnus-installer/target/test-classes/com/cygnus/installer/DeploymentWriterTest.class
new file mode 100644
index 0000000..4da717e
Binary files /dev/null and b/cygnus-installer/target/test-classes/com/cygnus/installer/DeploymentWriterTest.class differ
diff --git a/cygnus-installer/target/test-classes/com/cygnus/installer/DockerPrerequisiteCheckerTest$1.class b/cygnus-installer/target/test-classes/com/cygnus/installer/DockerPrerequisiteCheckerTest$1.class
new file mode 100644
index 0000000..eecb452
Binary files /dev/null and b/cygnus-installer/target/test-classes/com/cygnus/installer/DockerPrerequisiteCheckerTest$1.class differ
diff --git a/cygnus-installer/target/test-classes/com/cygnus/installer/DockerPrerequisiteCheckerTest.class b/cygnus-installer/target/test-classes/com/cygnus/installer/DockerPrerequisiteCheckerTest.class
index 4d8ec4e..96278c7 100644
Binary files a/cygnus-installer/target/test-classes/com/cygnus/installer/DockerPrerequisiteCheckerTest.class and b/cygnus-installer/target/test-classes/com/cygnus/installer/DockerPrerequisiteCheckerTest.class differ
diff --git a/cygnus-installer/target/test-classes/com/cygnus/installer/IniConfigurationLoaderTest.class b/cygnus-installer/target/test-classes/com/cygnus/installer/IniConfigurationLoaderTest.class
new file mode 100644
index 0000000..4d454e4
Binary files /dev/null and b/cygnus-installer/target/test-classes/com/cygnus/installer/IniConfigurationLoaderTest.class differ
diff --git a/cygnus-installer/target/test-classes/com/cygnus/installer/InstallationServiceTest.class b/cygnus-installer/target/test-classes/com/cygnus/installer/InstallationServiceTest.class
new file mode 100644
index 0000000..9bf196a
Binary files /dev/null and b/cygnus-installer/target/test-classes/com/cygnus/installer/InstallationServiceTest.class differ
diff --git a/cygnus-installer/target/test-classes/com/cygnus/installer/MachineAssertionServiceTest.class b/cygnus-installer/target/test-classes/com/cygnus/installer/MachineAssertionServiceTest.class
new file mode 100644
index 0000000..7e21845
Binary files /dev/null and b/cygnus-installer/target/test-classes/com/cygnus/installer/MachineAssertionServiceTest.class differ
diff --git a/cygnus-installer/target/test-classes/com/cygnus/installer/ProductProfileRegistryTest.class b/cygnus-installer/target/test-classes/com/cygnus/installer/ProductProfileRegistryTest.class
new file mode 100644
index 0000000..f391960
Binary files /dev/null and b/cygnus-installer/target/test-classes/com/cygnus/installer/ProductProfileRegistryTest.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/admin/controller/Admin.class b/cygnus-onprem-app/target/classes/matrix/nimble/admin/controller/Admin.class
index 8b647f6..5c97e29 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/admin/controller/Admin.class and b/cygnus-onprem-app/target/classes/matrix/nimble/admin/controller/Admin.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/MaintenanceHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/MaintenanceHandler.class
index 1f2d975..a633782 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/MaintenanceHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/MaintenanceHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioBranch.class b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioBranch.class
index 8650e9d..975f9eb 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioBranch.class and b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioBranch.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioHandler.class
index 8ab7911..8369d02 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/PortfolioHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/User.class b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/User.class
index f460a22..f621143 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/User.class and b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/User.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/UserHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/UserHandler.class
index 4d0ca6b..de75c55 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/UserHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/admin/model/UserHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisCacheService.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisCacheService.class
index 6c9ab64..a212558 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisCacheService.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisCacheService.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisConfiguration.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisConfiguration.class
index 3feab82..5fc25b5 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisConfiguration.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/cache/OnPremRedisConfiguration.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException$Reason.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException$Reason.class
index 5f2117d..ddca0a0 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException$Reason.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException$Reason.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException.class
index ca637fb..675594c 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationException.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationGateway.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationGateway.class
index 5ce5609..1046c65 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationGateway.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudAuthenticationGateway.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudIdentityConfiguration.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudIdentityConfiguration.class
index c52f91c..5b0f8ed 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudIdentityConfiguration.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudIdentityConfiguration.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudSessionMapper.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudSessionMapper.class
index a96f5d2..d9c9490 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudSessionMapper.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/CloudSessionMapper.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/SessionMenuRenderer.class b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/SessionMenuRenderer.class
index 0ca4dc0..4f4b88d 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/SessionMenuRenderer.class and b/cygnus-onprem-app/target/classes/matrix/nimble/cloud/identity/SessionMenuRenderer.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/controller/Ajax.class b/cygnus-onprem-app/target/classes/matrix/nimble/controller/Ajax.class
index a59fa80..0b516bf 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/controller/Ajax.class and b/cygnus-onprem-app/target/classes/matrix/nimble/controller/Ajax.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/controller/AjaxV2.class b/cygnus-onprem-app/target/classes/matrix/nimble/controller/AjaxV2.class
index 543054c..44e23c4 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/controller/AjaxV2.class and b/cygnus-onprem-app/target/classes/matrix/nimble/controller/AjaxV2.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/controller/CaseUpload.class b/cygnus-onprem-app/target/classes/matrix/nimble/controller/CaseUpload.class
index 04c8d6a..21f05dc 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/controller/CaseUpload.class and b/cygnus-onprem-app/target/classes/matrix/nimble/controller/CaseUpload.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/controller/DocAjax.class b/cygnus-onprem-app/target/classes/matrix/nimble/controller/DocAjax.class
index 54d7df8..2b5855a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/controller/DocAjax.class and b/cygnus-onprem-app/target/classes/matrix/nimble/controller/DocAjax.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/controller/General.class b/cygnus-onprem-app/target/classes/matrix/nimble/controller/General.class
index 6aaeabc..d7e92cc 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/controller/General.class and b/cygnus-onprem-app/target/classes/matrix/nimble/controller/General.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/controller/SessionController.class b/cygnus-onprem-app/target/classes/matrix/nimble/controller/SessionController.class
index 4fd58ec..07d6d5a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/controller/SessionController.class and b/cygnus-onprem-app/target/classes/matrix/nimble/controller/SessionController.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/controller/CutOff.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/controller/CutOff.class
index 2751247..f1ca5dd 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/controller/CutOff.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/controller/CutOff.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Allocation.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Allocation.class
index 3b053df..04af865 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Allocation.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Allocation.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/AutoCutThread.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/AutoCutThread.class
index 6d7b543..d9d24a9 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/AutoCutThread.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/AutoCutThread.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffList.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffList.class
index d84fd9a..c44a057 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffList.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffList.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffRecord.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffRecord.class
index 5ca2db2..e66c25a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffRecord.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/CutOffRecord.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/PhotoCases.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/PhotoCases.class
index a767cf7..626901f 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/PhotoCases.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/PhotoCases.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/ReferenceSheet.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/ReferenceSheet.class
index cec0e4a..3217190 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/ReferenceSheet.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/ReferenceSheet.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMS.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMS.class
index ff27bb3..a736f54 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMS.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMS.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMSRecord.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMSRecord.class
index ab792f3..ccbf92a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMSRecord.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SMSRecord.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SendToOperation.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SendToOperation.class
index 5e7f5af..b619fda 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SendToOperation.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/SendToOperation.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Telesheet.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Telesheet.class
index 661d29e..815d506 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Telesheet.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/cutoff/model/Telesheet.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/controller/Dedupe.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/controller/Dedupe.class
index 3d7d800..a5355ef 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/controller/Dedupe.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/controller/Dedupe.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDetails.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDetails.class
index 46ddea2..5aa87c7 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDetails.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDetails.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDo.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDo.class
index 5c440af..a5ecf65 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDo.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeDo.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeHandler.class
index 797cdf9..5fd5ca8 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRecord.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRecord.class
index afb16ad..4e3c0fb 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRecord.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRecord.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRun.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRun.class
index 67ca473..9fbcae6 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRun.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/DedupeRun.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/SendDedupe.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/SendDedupe.class
index fe155f4..05cc777 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/SendDedupe.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/dedupe/model/SendDedupe.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/controller/EDPDocuments.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/controller/EDPDocuments.class
index 26d379f..d59694f 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/controller/EDPDocuments.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/controller/EDPDocuments.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/DocTelesheet.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/DocTelesheet.class
index 0924e3c..d3e1915 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/DocTelesheet.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/DocTelesheet.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/EDPDocumentHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/EDPDocumentHandler.class
index 50f0464..803bcde 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/EDPDocumentHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/documents/model/EDPDocumentHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/output/model/ReportOutput.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/output/model/ReportOutput.class
index ffc1672..323186b 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/output/model/ReportOutput.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/output/model/ReportOutput.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/CasePucnhing.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/CasePucnhing.class
index 7c75583..2a1816b 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/CasePucnhing.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/CasePucnhing.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/EditCasesGrid.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/EditCasesGrid.class
index ea1fa2c..e9152e7 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/EditCasesGrid.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/EditCasesGrid.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/Punching.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/Punching.class
index 441b5d4..a540638 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/Punching.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/controller/Punching.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseDetails.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseDetails.class
index bea2579..42c061e 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseDetails.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseDetails.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseGrid.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseGrid.class
index f1f94ac..7484a5a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseGrid.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/CaseGrid.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/DocDetails.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/DocDetails.class
index 5c0e614..afea711 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/DocDetails.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/DocDetails.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/PunchingHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/PunchingHandler.class
index 2a1323c..db14e98 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/PunchingHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/punching/model/PunchingHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/controller/EDPTools.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/controller/EDPTools.class
index 5614e21..3e3aea3 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/controller/EDPTools.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/controller/EDPTools.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/AddEditProduct.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/AddEditProduct.class
index af5605b..4d27c36 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/AddEditProduct.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/AddEditProduct.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/ColonyFuncs.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/ColonyFuncs.class
index dfa4d0a..eb63604 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/ColonyFuncs.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/ColonyFuncs.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutOffPRecord.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutOffPRecord.class
index 1679bd0..e9ffa34 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutOffPRecord.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutOffPRecord.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutoffPending.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutoffPending.class
index dfee09a..fce08fb 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutoffPending.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/CutoffPending.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseDetails.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseDetails.class
index cb8d4e3..7d867ea 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseDetails.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseDetails.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseGrid.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseGrid.class
index 691c9a7..3a3da7f 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseGrid.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/DelCaseGrid.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/EdpToolsHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/EdpToolsHandler.class
index e6ba740..8382f93 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/EdpToolsHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/edp/tools/model/EdpToolsHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/hr/controller/HR.class b/cygnus-onprem-app/target/classes/matrix/nimble/hr/controller/HR.class
index 5ed6051..b5332ec 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/hr/controller/HR.class and b/cygnus-onprem-app/target/classes/matrix/nimble/hr/controller/HR.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/hr/model/EmployeeHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/hr/model/EmployeeHandler.class
index 9fafa52..b801c9e 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/hr/model/EmployeeHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/hr/model/EmployeeHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/MIS.class b/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/MIS.class
index 785d39e..ef7bab9 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/MIS.class and b/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/MIS.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/Monitoring.class b/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/Monitoring.class
index 059ccd7..6e2632d 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/Monitoring.class and b/cygnus-onprem-app/target/classes/matrix/nimble/mis/controller/Monitoring.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Employee.class b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Employee.class
index 2062948..df16324 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Employee.class and b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Employee.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Filters.class b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Filters.class
index 3af13dc..1a31405 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Filters.class and b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/Filters.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MISHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MISHandler.class
index 74262ff..0e77a1a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MISHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MISHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MonitoringHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MonitoringHandler.class
index bd1b7b0..9942e0f 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MonitoringHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/mis/model/MonitoringHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/model/DownloadUploadSettings.class b/cygnus-onprem-app/target/classes/matrix/nimble/model/DownloadUploadSettings.class
index 79c1e6c..c309462 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/model/DownloadUploadSettings.class and b/cygnus-onprem-app/target/classes/matrix/nimble/model/DownloadUploadSettings.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/model/GeneralHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/model/GeneralHandler.class
index a0dfff6..0c34def 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/model/GeneralHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/model/GeneralHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/model/Login.class b/cygnus-onprem-app/target/classes/matrix/nimble/model/Login.class
index fe5ad76..48197c3 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/model/Login.class and b/cygnus-onprem-app/target/classes/matrix/nimble/model/Login.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/model/LoginKey.class b/cygnus-onprem-app/target/classes/matrix/nimble/model/LoginKey.class
index 3fb90af..6e4bbcd 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/model/LoginKey.class and b/cygnus-onprem-app/target/classes/matrix/nimble/model/LoginKey.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/model/MailboxHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/model/MailboxHandler.class
index af12a42..33d5aa8 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/model/MailboxHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/model/MailboxHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/model/Session.class b/cygnus-onprem-app/target/classes/matrix/nimble/model/Session.class
index 474322d..4fb48c9 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/model/Session.class and b/cygnus-onprem-app/target/classes/matrix/nimble/model/Session.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/model/UploadHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/model/UploadHandler.class
index 77c728c..42be011 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/model/UploadHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/model/UploadHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/controller/OprDocuments.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/controller/OprDocuments.class
index 996fbe0..bff7480 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/controller/OprDocuments.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/controller/OprDocuments.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/BankDoc.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/BankDoc.class
index cc16a9c..ab5f965 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/BankDoc.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/BankDoc.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/OprDocumentHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/OprDocumentHandler.class
index c632ffc..73b727f 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/OprDocumentHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/documents/model/OprDocumentHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/BankReports.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/BankReports.class
index b6242d7..37e3897 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/BankReports.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/BankReports.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/TrackerGenerator.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/TrackerGenerator.class
index 72a9d13..d1c5c30 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/TrackerGenerator.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/controller/TrackerGenerator.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/BankReportHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/BankReportHandler.class
index 4ffe352..5bc300d 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/BankReportHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/BankReportHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CaseList.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CaseList.class
index f4412dd..c6dc2ec 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CaseList.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CaseList.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedExcelReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedExcelReporting.class
index 69ef413..f8fd97b 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedExcelReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedExcelReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedReporting.class
index 7c1bf9c..eddc46a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReporting.class
index c778acc..0112ce0 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReportingTabular.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReportingTabular.class
index 1c6e802..826f49b 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReportingTabular.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/CombinedWordlReportingTabular.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ExcelTrackers.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ExcelTrackers.class
index feedab0..3d13ee4 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ExcelTrackers.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ExcelTrackers.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartWiseReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartWiseReporting.class
index e30dcaa..d6e7eee 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartWiseReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartWiseReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartwiseExcelReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartwiseExcelReporting.class
index 5bd27d2..2bf758e 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartwiseExcelReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/PartwiseExcelReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor$ReportEmailThreadFactory.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor$ReportEmailThreadFactory.class
index b1c994e..1fc8884 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor$ReportEmailThreadFactory.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor$ReportEmailThreadFactory.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor.class
index a1d8356..8f7c6e3 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportEmailJobExecutor.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportSettings.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportSettings.class
index 5c71c03..bd663d1 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportSettings.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/ReportSettings.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/SendReports.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/SendReports.class
index 7ce0f7e..cdc46fd 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/SendReports.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/SendReports.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerGeneratorHelper.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerGeneratorHelper.class
index 08451c7..a05f258 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerGeneratorHelper.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerGeneratorHelper.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSetting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSetting.class
index 9ebd018..3ef75a2 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSetting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSetting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSheet.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSheet.class
index 7387962..680c427 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSheet.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/output/model/TrackerSheet.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/controller/Operations.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/controller/Operations.class
index 3fc965b..0c1b4f7 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/controller/Operations.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/controller/Operations.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/FinalDone.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/FinalDone.class
index ce7a856..ab395ea 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/FinalDone.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/FinalDone.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/NegUpdRequest.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/NegUpdRequest.class
index ebecece..894773c 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/NegUpdRequest.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/NegUpdRequest.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OfficeReport.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OfficeReport.class
index 4445b6e..752c8ff 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OfficeReport.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OfficeReport.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OperatorReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OperatorReporting.class
index c77b301..e0c4490 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OperatorReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OperatorReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OtherReport.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OtherReport.class
index 9b17e7c..7a5bd2d 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OtherReport.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/OtherReport.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/RefrenceReport.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/RefrenceReport.class
index 1adba57..04a043a 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/RefrenceReport.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/RefrenceReport.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ReportingHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ReportingHandler.class
index 2b09aa0..4618940 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ReportingHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ReportingHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ResidenceReport.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ResidenceReport.class
index 7f6eb2b..65b0523 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ResidenceReport.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ResidenceReport.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ScannerReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ScannerReporting.class
index 91e3d4b..a660730 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ScannerReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/ScannerReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReport.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReport.class
index f4200e1..b6d0824 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReport.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReport.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReporting.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReporting.class
index e8c58ea..defb0db 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReporting.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/reporting/model/TelecallingReporting.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/controller/OperationTools.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/controller/OperationTools.class
index a7e5e3e..608ec43 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/controller/OperationTools.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/controller/OperationTools.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedBelts.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedBelts.class
index 1b20109..be49bca 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedBelts.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedBelts.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedCases.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedCases.class
index 327eb51..ea578a5 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedCases.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AllocatedCases.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AppEmails.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AppEmails.class
index 4f8faa5..4e4a4aa 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AppEmails.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/AppEmails.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Belt.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Belt.class
index 0d852a0..9faa35e 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Belt.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Belt.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/BeltTransfer.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/BeltTransfer.class
index 2677033..c1f6e2c 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/BeltTransfer.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/BeltTransfer.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/CaseTransfer.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/CaseTransfer.class
index 0e29b3a..7b4414b 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/CaseTransfer.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/CaseTransfer.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Colony.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Colony.class
index 6464cf3..47bfafe 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Colony.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Colony.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/DocTagger.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/DocTagger.class
index dcc35d9..d216680 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/DocTagger.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/DocTagger.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Holiday.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Holiday.class
index cbef09c..24c5872 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Holiday.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Holiday.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/HolidayFilter.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/HolidayFilter.class
index 22a3fc3..9d19b97 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/HolidayFilter.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/HolidayFilter.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OclCases.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OclCases.class
index 5e073f7..621a894 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OclCases.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OclCases.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OperatorAllocation.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OperatorAllocation.class
index 44d637d..d7dd963 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OperatorAllocation.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/OperatorAllocation.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler$1.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler$1.class
index 38b1f27..f8c5a9d 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler$1.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler$1.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler.class
index 34c5c96..e6b414c 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/ToolsHandler.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Verifier.class b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Verifier.class
index 63a630a..45f073c 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Verifier.class and b/cygnus-onprem-app/target/classes/matrix/nimble/operation/tools/model/Verifier.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/CommonFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/CommonFunctions.class
index 03e789d..6b57937 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/CommonFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/CommonFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DBFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DBFunctions.class
index 1bbf996..249ad28 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DBFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DBFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabaseConnectionPool.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabaseConnectionPool.class
index f3f0b0f..20c5684 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabaseConnectionPool.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabaseConnectionPool.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabasePoolLifecycleListener.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabasePoolLifecycleListener.class
index e1fbed9..083b8b6 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabasePoolLifecycleListener.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/DatabasePoolLifecycleListener.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions$1.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions$1.class
index b9db753..977c429 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions$1.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions$1.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions.class
index abdb95b..4747e8d 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/EmailFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ExcelFormatter.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ExcelFormatter.class
index c4d5e11..346d095 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ExcelFormatter.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ExcelFormatter.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions$1.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions$1.class
index 7ef4099..62c2197 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions$1.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions$1.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions.class
index db6fae6..6968a1e 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FTPFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FileFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FileFunctions.class
index 3274573..d7b07ab 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FileFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/FileFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/GlobalClass.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/GlobalClass.class
index 1a50feb..a896aff 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/GlobalClass.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/GlobalClass.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/MSSQLFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/MSSQLFunctions.class
index b181194..0bb15a4 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/MSSQLFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/MSSQLFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ModuleFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ModuleFunctions.class
index 9e6111c..b636dea 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ModuleFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ModuleFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/NimbleException.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/NimbleException.class
index 3853560..97cdc61 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/NimbleException.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/NimbleException.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/PDFFormatter.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/PDFFormatter.class
index 0ea6271..19a16c4 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/PDFFormatter.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/PDFFormatter.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/SMSFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/SMSFunctions.class
index 8daa073..8fbaf72 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/SMSFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/SMSFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/StringFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/StringFunctions.class
index 69efc57..b898fe4 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/StringFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/StringFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/TPDBFunctions.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/TPDBFunctions.class
index 8d2725d..9731933 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/TPDBFunctions.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/TPDBFunctions.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell$Border.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell$Border.class
index b49c469..0153cfe 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell$Border.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell$Border.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell.class
index 6acdbc4..a841677 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/XLCell.class differ
diff --git a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ZipUtility.class b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ZipUtility.class
index 63aef9c..7e01eaa 100644
Binary files a/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ZipUtility.class and b/cygnus-onprem-app/target/classes/matrix/nimble/utilities/ZipUtility.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/BranchMigrationTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/BranchMigrationTest.class
index 8472182..034fc5c 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/BranchMigrationTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/BranchMigrationTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/DatabaseAuditRunner.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/DatabaseAuditRunner.class
index f2d89a3..ca8ea80 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/DatabaseAuditRunner.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/DatabaseAuditRunner.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/DevelopmentLauncherTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/DevelopmentLauncherTest.class
index fafd609..09df52d 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/DevelopmentLauncherTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/DevelopmentLauncherTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/EmbeddedTomcatServer.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/EmbeddedTomcatServer.class
index b509cf8..64b165c 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/EmbeddedTomcatServer.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/EmbeddedTomcatServer.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/FileFunctionsQueryCacheTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/FileFunctionsQueryCacheTest.class
index 30da7c2..8113d9c 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/FileFunctionsQueryCacheTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/FileFunctionsQueryCacheTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/HomeShellStructureTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/HomeShellStructureTest.class
index 8ee7ec4..7876cd2 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/HomeShellStructureTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/HomeShellStructureTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/ManageUsersMigrationTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/ManageUsersMigrationTest.class
index 780213a..ae8b18e 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/ManageUsersMigrationTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/ManageUsersMigrationTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/RoleVisibleBatchMigrationTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/RoleVisibleBatchMigrationTest.class
index 1e0b657..d3044ce 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/RoleVisibleBatchMigrationTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/RoleVisibleBatchMigrationTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/SpringWebContextTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/SpringWebContextTest.class
index 87f615e..7eb16eb 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/SpringWebContextTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/SpringWebContextTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/TomcatUiIT.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/TomcatUiIT.class
index ff460fd..be8427c 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/TomcatUiIT.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/TomcatUiIT.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/CloudSessionMapperTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/CloudSessionMapperTest.class
index 87ba7df..fda789b 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/CloudSessionMapperTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/CloudSessionMapperTest.class differ
diff --git a/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/SessionMenuRendererTest.class b/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/SessionMenuRendererTest.class
index f48ab48..5a47c57 100644
Binary files a/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/SessionMenuRendererTest.class and b/cygnus-onprem-app/target/test-classes/matrix/nimble/cloud/identity/SessionMenuRendererTest.class differ
diff --git a/docs/client-registration-installation-runbook.md b/docs/client-registration-installation-runbook.md
index 70741e4..370611b 100644
--- a/docs/client-registration-installation-runbook.md
+++ b/docs/client-registration-installation-runbook.md
@@ -6,8 +6,9 @@
2. One or more tenant accounts are attached to that registration.
3. A time-bound license defines package, user, and installation limits.
4. An activation key is generated, stored only as a BCrypt hash, and emailed.
-5. The Java wizard blocks unless Docker, Docker Engine, and Compose v2 work.
-6. The wizard validates the key, generates an RSA-3072 installation key, and
+5. The Technobee Service Installer blocks unless Docker, Docker Engine, and
+ Compose v2 work.
+6. The installer validates the key, generates an RSA-3072 installation key, and
registers the installation in one database transaction.
7. The plaintext activation key is neither returned again nor written locally.
8. Runtime token issuance requires an active registration, tenant, license, and
@@ -51,27 +52,45 @@ For replacements:
Both require a non-empty reason, invalidate the cached installation, increment
its security version, and write an audit event.
-## Running the wizard
+## Running the Technobee Service Installer
```bash
mvn -pl cygnus-installer -am package
-CYGNUS_CLOUD_URL=https://cloud.example.com \
-java -jar cygnus-installer/target/cygnus-installer-1.0.0-SNAPSHOT.jar
+TECHNOBEE_INSTALLER_CONFIG=cygnus-installer/config/cygnus-installer.ini \
+java -jar cygnus-installer/target/technobee-service-installer-1.0.0-SNAPSHOT.jar
```
-After a successful run, review the generated `compose.yml`, set
-`CYGNUS_IMAGE`, and start with `docker compose up -d`.
+This opens the Swing installation wizard. Add `--cli` when running on a
+headless server or when the terminal workflow is preferred.
-The wizard asks for the output directory. Press Enter to accept
-`CYGNUS_INSTALL_OUTPUT`, which defaults to `./cygnus-installation`. It creates:
+Select Matrix or Cygnus using the INI `product` property. The INI also supplies
+the cloud URL, installation API base path, environment, output directory, and
+the product profile. No cloud URL, route, service name, or filesystem path is
+compiled into the installer workflow.
+
+The installer asks for the Matrix or Cygnus Docker image and writes it to
+`.env` using the selected profile's image variable. After a successful run,
+review `compose.yml` and `.env`, then start with `docker compose up -d`.
+
+The installer asks for the output directory. Press Enter to accept the INI
+`output_directory`. It creates:
- `compose.yml`
+- `.env`
- `config/installation.yml`
+- `config/machine-assertion.jwt`
- `config/keys/client-signing-private.pem`
- `config/keys/client-signing-public.pem`
The generated private key must remain readable only by the service account.
-Never email or copy it to the cloud. The cloud stores only its public key.
+Never email or copy it to the cloud. The encrypted machine assertion and
+private key remain on premises; the cloud receives and stores only the public
+key. The generated service configuration records the returned client ID,
+installation ID/code, cloud URL, assertion path, and key paths.
+
+The installer does not connect directly to PostgreSQL or Redis. Registration,
+license enforcement, and installation identity remain the selected cloud
+service's responsibility.
## Operational checks