Refactoring UserCacheService, adesso sfrutta EntityCache più che il caching integrato.
All checks were successful
IntegryManagementSystem_Multi/pipeline/head This commit looks good

This commit is contained in:
2025-12-01 13:05:59 +01:00
parent 6c2eaaa37a
commit 8d35f9284a
10 changed files with 271 additions and 270 deletions

View File

@@ -69,7 +69,6 @@ public class EmsCoreDBLoader {
try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager(connectionPool)){ try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager(connectionPool)){
discoverAllConnections(multiDBTransactionManager); discoverAllConnections(multiDBTransactionManager);
setupAzienda(multiDBTransactionManager); setupAzienda(multiDBTransactionManager);
userCacheService.discoverAllUsers(multiDBTransactionManager);
if (onComplete != null) onComplete.run(multiDBTransactionManager); if (onComplete != null) onComplete.run(multiDBTransactionManager);
} catch (Exception ex) { } catch (Exception ex) {

View File

@@ -35,9 +35,10 @@ public class DbmsChangeTrackerComponent {
add(StbEditLimit.ENTITY); add(StbEditLimit.ENTITY);
add(StbGestSetup.ENTITY); add(StbGestSetup.ENTITY);
add(StbGestSetupDepo.ENTITY); add(StbGestSetupDepo.ENTITY);
add(WtbGestSetupUser.ENTITY); add(StbUser.ENTITY);
add(WtbClie.ENTITY);
add(WtbDepo.ENTITY); add(WtbDepo.ENTITY);
add(WtbGestSetupUser.ENTITY);
}}; }};

View File

@@ -44,6 +44,14 @@ public class EntityCacheComponent implements ApplicationListener {
private final HashMap<IntegryCustomerDB, ConcurrentHashMap<String, ConcurrentHashMap<HashMap<String, Object>, EntityBase>>> entityCache = new HashMap<>(); private final HashMap<IntegryCustomerDB, ConcurrentHashMap<String, ConcurrentHashMap<HashMap<String, Object>, EntityBase>>> entityCache = new HashMap<>();
// Lock per IntegryCustomerDB per garantire accessi sincronizzati alla cache di quel customer
private final ConcurrentHashMap<IntegryCustomerDB, Object> cacheLocks = new ConcurrentHashMap<>();
private Object getCacheLock(IntegryCustomerDB customerDB) {
cacheLocks.putIfAbsent(customerDB, new Object());
return cacheLocks.get(customerDB);
}
private final HashMap<String, Class<? extends EntityBase>> enabledEntities = new HashMap<String, Class<? extends EntityBase>>() {{ private final HashMap<String, Class<? extends EntityBase>> enabledEntities = new HashMap<String, Class<? extends EntityBase>>() {{
put(MtbAart.ENTITY, MtbAart.class); put(MtbAart.ENTITY, MtbAart.class);
put(MtbAartBarCode.ENTITY, MtbAartBarCode.class); put(MtbAartBarCode.ENTITY, MtbAartBarCode.class);
@@ -52,9 +60,10 @@ public class EntityCacheComponent implements ApplicationListener {
put(StbEditLimit.ENTITY, StbEditLimit.class); put(StbEditLimit.ENTITY, StbEditLimit.class);
put(StbGestSetup.ENTITY, StbGestSetup.class); put(StbGestSetup.ENTITY, StbGestSetup.class);
put(StbGestSetupDepo.ENTITY, StbGestSetupDepo.class); put(StbGestSetupDepo.ENTITY, StbGestSetupDepo.class);
put(WtbGestSetupUser.ENTITY, WtbGestSetupUser.class); put(StbUser.ENTITY, StbUser.class);
put(WtbDepo.ENTITY, WtbDepo.class); put(WtbDepo.ENTITY, WtbDepo.class);
put(WtbGestSetupUser.ENTITY, WtbGestSetupUser.class);
put(WtbClie.ENTITY, WtbClie.class);
}}; }};
public EntityCacheComponent(DbmsChangeTrackerComponent dbmsChangeTrackerComponent, EntityPropertyHolder entityPropertyHolder) { public EntityCacheComponent(DbmsChangeTrackerComponent dbmsChangeTrackerComponent, EntityPropertyHolder entityPropertyHolder) {
@@ -103,20 +112,23 @@ public class EntityCacheComponent implements ApplicationListener {
} }
private void refreshCacheForEntity(Connection connection, IntegryCustomerDB customerDB, String tableName) throws Exception { private void refreshCacheForEntity(Connection connection, IntegryCustomerDB customerDB, String tableName) throws Exception {
Class<? extends EntityBase> clazz = enabledEntities.get(tableName); // Sincronizziamo l'intera operazione di refresh per il customerDB per evitare accessi concorrenti
synchronized (getCacheLock(customerDB)) {
Class<? extends EntityBase> clazz = enabledEntities.get(tableName);
// if (clazz == null) // if (clazz == null)
// throw new RuntimeException("Entity cache is not enabled for table " + tableName); // throw new RuntimeException("Entity cache is not enabled for table " + tableName);
entityCache.putIfAbsent(customerDB, new ConcurrentHashMap<>()); entityCache.putIfAbsent(customerDB, new ConcurrentHashMap<>());
entityCache.get(customerDB).remove(tableName); entityCache.get(customerDB).remove(tableName);
ConcurrentHashMap<HashMap<String, Object>, EntityBase> entities = retrieveEntityList(connection, tableName, clazz); ConcurrentHashMap<HashMap<String, Object>, EntityBase> entities = retrieveEntityList(connection, tableName, clazz);
entityCache.get(customerDB).put(tableName, entities); entityCache.get(customerDB).put(tableName, entities);
logger.trace(String.format("[%s] Cached %d records for entity %s", logger.trace(String.format("[%s] Cached %d records for entity %s",
customerDB.getValue(), customerDB.getValue(),
entities.size(), entities.size(),
clazz.getSimpleName())); clazz.getSimpleName()));
}
} }
public <T extends EntityBase> List<T> getCachedEntitiesList(IntegryCustomerDB customerDB, String tableName, Predicate<T> filterPredicate) { public <T extends EntityBase> List<T> getCachedEntitiesList(IntegryCustomerDB customerDB, String tableName, Predicate<T> filterPredicate) {
@@ -125,20 +137,27 @@ public class EntityCacheComponent implements ApplicationListener {
} }
public <T extends EntityBase> Stream<T> getCachedEntitiesStream(IntegryCustomerDB customerDB, String tableName, Predicate<T> filterPredicate) { public <T extends EntityBase> Stream<T> getCachedEntitiesStream(IntegryCustomerDB customerDB, String tableName, Predicate<T> filterPredicate) {
if (!isCacheEnabled(customerDB, tableName)) { // Per evitare accessi concorrenti leggiamo/snapshottiamo la cache sotto lock per quel customerDB
try { List<T> snapshot;
refreshCacheForEntity(customerDB, tableName); synchronized (getCacheLock(customerDB)) {
} catch (Exception e) { if (!isCacheEnabled(customerDB, tableName)) {
throw new RuntimeException(e); try {
refreshCacheForEntity(customerDB, tableName);
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
// prendo un'istantanea degli oggetti clonati per poter lavorare fuori dal lock
snapshot = entityCache.get(customerDB)
.get(tableName)
.values()
.stream()
.map(x -> (T) x.clone())
.collect(Collectors.toList());
} }
return entityCache.get(customerDB).get(tableName) return snapshot.stream().filter(filterPredicate);
.values()
.parallelStream()
.map(x -> (T) x)
.filter(filterPredicate)
.map(x -> (T) x.clone());
} }
@@ -176,9 +195,12 @@ public class EntityCacheComponent implements ApplicationListener {
event.getPrimaryKey()); event.getPrimaryKey());
entityCache.get(event.getCustomerDB()) // sincronizziamo la modifica per il customerDB
.get(event.getTableName()) synchronized (getCacheLock(event.getCustomerDB())) {
.put(entityPrimaryKey, newItem); entityCache.get(event.getCustomerDB())
.get(event.getTableName())
.put(entityPrimaryKey, newItem);
}
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -195,9 +217,13 @@ public class EntityCacheComponent implements ApplicationListener {
enabledEntities.get(event.getTableName()), enabledEntities.get(event.getTableName()),
event.getPrimaryKey()); event.getPrimaryKey());
entityCache.get(event.getCustomerDB())
.get(event.getTableName()) // sincronizziamo la modifica per il customerDB
.put(entityPrimaryKey, newItem); synchronized (getCacheLock(event.getCustomerDB())) {
entityCache.get(event.getCustomerDB())
.get(event.getTableName())
.put(entityPrimaryKey, newItem);
}
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@@ -210,12 +236,17 @@ public class EntityCacheComponent implements ApplicationListener {
HashMap<String, Object> entityPrimaryKey = convertSqlMapToEntityMap(event.getPrimaryKey(), enabledEntities.get(event.getTableName())); HashMap<String, Object> entityPrimaryKey = convertSqlMapToEntityMap(event.getPrimaryKey(), enabledEntities.get(event.getTableName()));
final EntityBase removedItem = entityCache.get(event.getCustomerDB()) // sincronizziamo la rimozione per il customerDB
.get(event.getTableName()) final EntityBase removedItem;
.remove(entityPrimaryKey); synchronized (getCacheLock(event.getCustomerDB())) {
removedItem = entityCache.get(event.getCustomerDB())
.get(event.getTableName())
.remove(entityPrimaryKey);
}
} }
private void handleTableTrackingResetted(TableTrackingResettedEvent event) throws Exception { private void handleTableTrackingResetted(TableTrackingResettedEvent event) throws Exception {
// reset e refresh sono eseguiti in modo sincronizzato per quel customer
resetTablesCache(event.getCustomerDB()); resetTablesCache(event.getCustomerDB());
refreshCacheGlobal(event.getCustomerDB()); refreshCacheGlobal(event.getCustomerDB());
} }
@@ -267,14 +298,19 @@ public class EntityCacheComponent implements ApplicationListener {
private void resetTableCache(IntegryCustomerDB customerDB, String tableName) { private void resetTableCache(IntegryCustomerDB customerDB, String tableName) {
if (entityCache.containsKey(customerDB) && entityCache.get(customerDB).containsKey(tableName)) { synchronized (getCacheLock(customerDB)) {
entityCache.get(customerDB).remove(tableName); if (entityCache.containsKey(customerDB) && entityCache.get(customerDB).containsKey(tableName)) {
entityCache.get(customerDB).remove(tableName);
}
} }
} }
private void resetTablesCache(IntegryCustomerDB customerDB) { private void resetTablesCache(IntegryCustomerDB customerDB) {
entityCache.remove(customerDB); // sincronizziamo la rimozione dell'intera cache per il customer
synchronized (getCacheLock(customerDB)) {
entityCache.remove(customerDB);
}
} }

View File

@@ -6,6 +6,7 @@ import it.integry.ems_model.entity.StbUser;
import it.integry.ems_model.entity.WtbUsers; import it.integry.ems_model.entity.WtbUsers;
import it.integry.ems_model.types.OperationType; import it.integry.ems_model.types.OperationType;
import it.integry.ems_model.utility.UtilityDB; import it.integry.ems_model.utility.UtilityDB;
import it.integry.ems_model.utility.UtilityLocalDate;
import it.integry.ems_model.utility.UtilityString; import it.integry.ems_model.utility.UtilityString;
import it.integry.security.utility.CryptoUtils; import it.integry.security.utility.CryptoUtils;
@@ -57,7 +58,7 @@ public class Migration_20220413102657 extends BaseMigration implements Migration
.setUserCode(wtbUser.getUserCode()) .setUserCode(wtbUser.getUserCode())
.setDetails(wtbUser.getDetails()) .setDetails(wtbUser.getDetails())
.setLastAccessDatetime(wtbUser.getLastAccessDatetime()) .setLastAccessDatetime(wtbUser.getLastAccessDatetime())
.setPasswordEndtime(wtbUser.getPasswordEndtime()) .setPasswordEndtime(UtilityLocalDate.localDateTimeFromDate(wtbUser.getPasswordEndtime()))
.setUrlCss(wtbUser.getUrlCss()) .setUrlCss(wtbUser.getUrlCss())
.setCodLang(wtbUser.getCodLang()) .setCodLang(wtbUser.getCodLang())
.setCreationDatetime(wtbUser.getCreationDatetime()) .setCreationDatetime(wtbUser.getCreationDatetime())

View File

@@ -1,29 +1,26 @@
package it.integry.ems.user.service; package it.integry.ems.user.service;
import it.integry.annotations.PostContextConstruct;
import it.integry.ems.dynamic_cache.EntityCacheComponent; import it.integry.ems.dynamic_cache.EntityCacheComponent;
import it.integry.ems.migration._base.IntegryCustomerDB;
import it.integry.ems.model.IntegryApplicationEnum; import it.integry.ems.model.IntegryApplicationEnum;
import it.integry.ems.settings.Model.AvailableConnectionModel; import it.integry.ems.settings.Model.AvailableConnectionModel;
import it.integry.ems.settings.Model.SettingsModel; import it.integry.ems.settings.Model.SettingsModel;
import it.integry.ems.sync.MultiDBTransaction.Connection;
import it.integry.ems.sync.MultiDBTransaction.MultiDBTransactionManager;
import it.integry.ems.task.TaskExecutorService;
import it.integry.ems.user.dto.UserDTO; import it.integry.ems.user.dto.UserDTO;
import it.integry.ems_model.entity.StbUser; import it.integry.ems_model.entity.StbUser;
import it.integry.ems_model.entity.WtbClie;
import it.integry.ems_model.entity.WtbDepo; import it.integry.ems_model.entity.WtbDepo;
import it.integry.ems_model.utility.UtilityDB;
import it.integry.ems_model.utility.UtilityHash; import it.integry.ems_model.utility.UtilityHash;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.time.LocalDateTime;
import java.util.concurrent.Callable; import java.util.ArrayList;
import java.util.concurrent.TimeUnit; import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.Optional;
import java.util.stream.Collectors;
@Service @Service
public class UserCacheService { public class UserCacheService {
@@ -31,73 +28,22 @@ public class UserCacheService {
@Autowired @Autowired
private SettingsModel settingsModel; private SettingsModel settingsModel;
@Autowired
private TaskExecutorService taskExecutorService;
@Autowired @Autowired
private EntityCacheComponent entityCacheComponent; private EntityCacheComponent entityCacheComponent;
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
private final HashMap<String, List<UserDTO>> cachedUsers = new HashMap<>();
private final ReentrantLock cacheLock = new ReentrantLock();
boolean canStart = false;
@PostContextConstruct(priority = 10)
private void init() {
canStart = true; //!UtilityDebug.isDebugExecution();
}
@Scheduled(fixedDelay = 5, timeUnit = TimeUnit.MINUTES)
private void internalCacheUpdate() {
internalCacheUpdate(false);
}
private void internalCacheUpdate(boolean forceStart) {
if (!forceStart && !canStart) return;
List<AvailableConnectionModel> availableConnectionModels =
settingsModel.getAvailableConnectionsWithoutDuplicatedProfiles(true);
try (MultiDBTransactionManager multiDBTransactionManager = new MultiDBTransactionManager()) {
for (AvailableConnectionModel model : availableConnectionModels) {
try {
multiDBTransactionManager.addConnection(model);
} catch (Exception ex) {
logger.info(String.format("Cannot find %s database", model.getDbName()), ex);
}
}
this.discoverAllUsers(multiDBTransactionManager);
} catch (Exception ex) {
logger.error("Refresh user cache", ex);
}
}
private void cache(String dbName, UserDTO user) {
cachedUsers.putIfAbsent(dbName, new ArrayList<>());
List<UserDTO> users = cachedUsers.get(dbName);
Optional<UserDTO> existentUser = users.stream()
.filter(x -> x.getUsername().equalsIgnoreCase(user.getUsername()))
.findFirst();
existentUser.ifPresent(users::remove);
users.add(user);
}
public List<String> retrieveProfilesOfUser(String username, String password, IntegryApplicationEnum application) { public List<String> retrieveProfilesOfUser(String username, String password, IntegryApplicationEnum application) {
ArrayList<String> profiles = new ArrayList<>(); ArrayList<String> profiles = new ArrayList<>();
for (Map.Entry<String, List<UserDTO>> users : cachedUsers.entrySet()) { final List<AvailableConnectionModel> availableConnections = settingsModel.getAvailableConnectionsWithoutDuplicatedProfiles(true);
final UserDTO foundUser = retrieveUser(users.getKey(), username, password, application);
for (AvailableConnectionModel availableConnection : availableConnections) {
final UserDTO foundUser = retrieveUser(availableConnection.getDbName(), username, password, application);
if (foundUser != null) { if (foundUser != null) {
profiles.add(settingsModel.getProfileDbFromDbName(users.getKey())); profiles.add(availableConnection.getProfileName());
} }
} }
@@ -105,152 +51,118 @@ public class UserCacheService {
} }
public @Nullable UserDTO retrieveUser(String dbName, String md5User) { public @Nullable UserDTO retrieveUser(String dbName, String md5User) {
cacheLock.lock(); List<UserDTO> users = internalUsersRetrieve(IntegryCustomerDB.parse(dbName), null);
try {
List<UserDTO> users = cachedUsers.getOrDefault(dbName, null);
if (users == null || users.isEmpty()) if (users == null || users.isEmpty())
return null; return null;
if (md5User == null || md5User.isEmpty()) if (md5User == null || md5User.isEmpty())
return null; return null;
final Optional<UserDTO> foundUser = users.stream() final Optional<UserDTO> foundUser = users.stream()
.filter(x -> { .filter(x -> {
String md5Hash = UtilityHash.generateMd5(String.format("%s%s", x.getUsername().toLowerCase(), x.getPassword().toLowerCase())); String md5Hash = UtilityHash.generateMd5(String.format("%s%s", x.getUsername().toLowerCase(), x.getPassword().toLowerCase()));
return md5Hash.contentEquals(md5User); return md5Hash.contentEquals(md5User);
}) })
.findFirst(); .findFirst();
return foundUser.orElse(null);
return foundUser.orElse(null);
} finally {
cacheLock.unlock();
}
} }
public @Nullable UserDTO retrieveUser(String dbName, String username, String password, IntegryApplicationEnum application) { public @Nullable UserDTO retrieveUser(String dbName, String username, String password, IntegryApplicationEnum application) {
cacheLock.lock(); List<UserDTO> users = internalUsersRetrieve(IntegryCustomerDB.parse(dbName), username);
try {
List<UserDTO> users = cachedUsers.getOrDefault(dbName, null);
if (users == null || users.isEmpty()) if (users == null || users.isEmpty())
return null; return null;
if (password == null || password.isEmpty()) if (password == null || password.isEmpty())
return null; return null;
String finalPasswordHex = UtilityHash.generateHash(password.toUpperCase()); String finalPasswordHex = UtilityHash.generateHash(password.toUpperCase());
final Optional<UserDTO> foundUser = users.stream() final Optional<UserDTO> foundUser = users.stream()
.filter(x -> x.getUsername().equalsIgnoreCase(username) && .filter(x -> x.isAttivo() &&
x.isAttivo() && x.getPasswordHash().contentEquals(finalPasswordHex) &&
x.getPasswordHash().contentEquals(finalPasswordHex) && (application == null ||
(application == null || (application == IntegryApplicationEnum.PVM && x.isWeb()) ||
(application == IntegryApplicationEnum.PVM && x.isWeb()) || (application == IntegryApplicationEnum.CONSEGNA && x.isWeb()) ||
(application == IntegryApplicationEnum.CONSEGNA && x.isWeb()) || (application == IntegryApplicationEnum.WMS && x.isWeb()) ||
(application == IntegryApplicationEnum.WMS && x.isWeb()) || (application == IntegryApplicationEnum.TASK && x.isWeb()) ||
(application == IntegryApplicationEnum.TASK && x.isWeb()) || (application == IntegryApplicationEnum.SALESBOOK && x.isWeb()) ||
(application == IntegryApplicationEnum.SALESBOOK && x.isWeb()) || (application == IntegryApplicationEnum.WINCLOCK && x.isWeb()) ||
(application == IntegryApplicationEnum.WINCLOCK && x.isWeb()) || (application == IntegryApplicationEnum.GESTIONALE_BASE && x.isInternal())))
(application == IntegryApplicationEnum.GESTIONALE_BASE && x.isInternal()))) .findFirst();
.findFirst();
return foundUser.orElse(null);
return foundUser.orElse(null);
} finally {
cacheLock.unlock();
}
} }
public @Nullable UserDTO retrieveUserData(String profileDb, String username, IntegryApplicationEnum application) { public @Nullable UserDTO retrieveUserData(String profileDb, String username, IntegryApplicationEnum application) {
cacheLock.lock(); String dbName = settingsModel.getDbNameFromProfileDb(profileDb);
try {
String dbName = settingsModel.getDbNameFromProfileDb(profileDb);
List<UserDTO> users = cachedUsers.getOrDefault(dbName, null); List<UserDTO> users = internalUsersRetrieve(IntegryCustomerDB.parse(dbName), username);
if (users == null || users.isEmpty()) if (users == null || users.isEmpty())
return null; return null;
final Optional<UserDTO> foundUser = users.stream() final Optional<UserDTO> foundUser = users.stream()
.filter(x -> x.getUsername().equalsIgnoreCase(username) && .filter(x -> (application == null ||
(application == null || (application == IntegryApplicationEnum.PVM && x.isWeb()) ||
(application == IntegryApplicationEnum.PVM && x.isWeb()) || (application == IntegryApplicationEnum.CONSEGNA && x.isWeb()) ||
(application == IntegryApplicationEnum.CONSEGNA && x.isWeb()) || (application == IntegryApplicationEnum.WMS && x.isWeb()) ||
(application == IntegryApplicationEnum.WMS && x.isWeb()) || (application == IntegryApplicationEnum.TASK && x.isWeb()) ||
(application == IntegryApplicationEnum.TASK && x.isWeb()) || (application == IntegryApplicationEnum.SALESBOOK && x.isWeb()) ||
(application == IntegryApplicationEnum.SALESBOOK && x.isWeb()) || (application == IntegryApplicationEnum.WINCLOCK && x.isWeb()) ||
(application == IntegryApplicationEnum.WINCLOCK && x.isWeb()) || (application == IntegryApplicationEnum.GESTIONALE_BASE && x.isInternal())))
(application == IntegryApplicationEnum.GESTIONALE_BASE && x.isInternal()))) .findFirst();
.findFirst();
return foundUser.orElse(null); return foundUser.orElse(null);
} finally {
cacheLock.unlock();
}
} }
public void discoverAllUsers(MultiDBTransactionManager multiDBTransactionManager) throws Exception { private List<UserDTO> internalUsersRetrieve(IntegryCustomerDB customerDB, String username) {
cacheLock.lock(); return entityCacheComponent.<StbUser>getCachedEntitiesStream(
try { customerDB,
List<Callable<Void>> calls = new ArrayList<>(); StbUser.ENTITY,
x -> x.getPasswordDecoded() != null && (username == null || x.getUserName().equalsIgnoreCase(username)))
for (final Connection connection : multiDBTransactionManager.getActiveConnections()) { .map(x -> {
calls.add(() -> { UserDTO userDTO = new UserDTO()
try { .setProfileDb(settingsModel.getProfileDbFromDbName(customerDB.getValue()))
.setUsername(x.getUserName())
String sql = "SELECT su.user_name,\n" + .setPassword(x.getPasswordDecoded())
" dbo.sys_dcd_pss(su.password) AS password, \n" + .setPasswordHash(UtilityHash.generateHash(x.getPasswordDecoded().toUpperCase()))
" CONVERT(varchar(max), HASHBYTES('SHA2_512', UPPER(dbo.sys_dcd_pss(su.password))),2) AS password_hash,\n" + .setKeyGroup(x.getKeyGroup())
" su.key_group,\n" + .setFullname(x.getFullName())
" su.full_name,\n" + .setEmail(x.geteMail())
" su.e_mail,\n" + .setLastAccessDatetime(x.getLastAccessDatetime())
" su.last_access_datetime,\n" + .setPasswordEndtime(x.getPasswordEndtime())
" su.password_endtime,\n" + .setCodLang(x.getCodLang())
" su.cod_lang,\n" + .setFlagPasswordExpiring(x.getFlagPasswordExpiring() != null ? x.getFlagPasswordExpiring().charAt(0) : null)
" su.flag_password_expiring,\n" + .setPasswordExpired(x.getPasswordEndtime() != null
" CAST(IIF(su.password_endtime IS NOT NULL AND\n" + && LocalDateTime.now().isAfter(x.getPasswordEndtime())
" DATEDIFF(DAY, su.password_endtime, GETDATE()) > 0 AND su.flag_password_expiring = 'S', 1,\n" + && "S".equalsIgnoreCase(x.getFlagPasswordExpiring()))
" 0) AS BIT) AS is_password_expired,\n" + .setUserCode(x.getUserCode()) //To be customized
" IIF(su.key_group = '3' AND su.user_code IS NULL, wc.cod_anag, su.user_code) AS user_code,\n" + .setAttivo("S".equalsIgnoreCase(x.getFlagAttivo()))
" CAST(IIF(ISNULL(su.flag_attivo, 'N') = 'S', 1, 0) AS BIT) AS is_attivo,\n" + .setInternal("S".equalsIgnoreCase(x.getFlagIntraUser()) || "S".equalsIgnoreCase(x.getFlagDba()))
" CAST(IIF(su.flag_intra_user = 'S' OR su.flag_dba = 'S', 1, 0) AS BIT) AS is_internal,\n" + .setWeb("S".equalsIgnoreCase(x.getFlagIntraUser()) || "S".equalsIgnoreCase(x.getFlagExtraUser()));
" CAST(IIF(su.flag_intra_user = 'S' OR su.flag_extra_user = 'S', 1, 0) AS BIT) AS is_web,\n" +
" '" + connection.getProfileName() + "' AS profile_db\n" +
"FROM " + StbUser.ENTITY + " su " +
" LEFT OUTER JOIN wtb_clie wc ON su.user_name = wc.user_name\n" +
"WHERE dbo.sys_dcd_pss(su.password) IS NOT NULL";
final List<UserDTO> userDTOS = UtilityDB.executeSimpleQueryDTO(connection, sql, UserDTO.class); if (userDTO.getKeyGroup() != null && userDTO.getKeyGroup() == 3) {
final List<WtbClie> wtbClie = entityCacheComponent.getCachedEntitiesList(customerDB, WtbClie.ENTITY,
y -> y.getUserName().equalsIgnoreCase(userDTO.getUsername()));
if (userDTOS != null) if (!wtbClie.isEmpty())
userDTOS.forEach(x -> { userDTO.setUserCode(wtbClie.get(0).getCodAnag());
List<WtbDepo> availableDepoList = entityCacheComponent.getCachedEntitiesList(connection.getIntegryCustomerDB(), WtbDepo.ENTITY,
y -> x.getUsername().equalsIgnoreCase(y.getUserName())
);
x.setAvailableDepoList(availableDepoList);
cache(connection.getDbName(), x);
});
} catch (Exception ex) {
logger.error(String.format("Errore durante la retrieve degli utenti su \"%s\". %s", connection.getProfileName(), ex.getMessage()), ex);
} }
return null; List<WtbDepo> availableDepoList = entityCacheComponent.getCachedEntitiesList(customerDB, WtbDepo.ENTITY,
}); y -> x.getUsername().equalsIgnoreCase(y.getUserName())
} );
userDTO.setAvailableDepoList(availableDepoList);
taskExecutorService.executeTasks(calls); return userDTO;
} finally { })
cacheLock.unlock(); .collect(Collectors.toList());
}
} }
public void invalidateCache() {
cacheLock.lock();
this.cachedUsers.clear();
cacheLock.unlock();
this.internalCacheUpdate(true);
}
} }

View File

@@ -45,7 +45,7 @@ public class UserRegistrationService {
.setPassword(userRegistrationDTO.getPassword()) .setPassword(userRegistrationDTO.getPassword())
.seteMail(userRegistrationDTO.getEmail()) .seteMail(userRegistrationDTO.getEmail())
.setUserNameRif(userRegistrationDTO.getCodAzienda()) .setUserNameRif(userRegistrationDTO.getCodAzienda())
.setPasswordEndtime(EmsRestConstants.DATE_NULL) .setPasswordEndtime(EmsRestConstants.LOCAL_DATE_TIME_NULL)
.setKeyGroup(userRegistrationDTO.getKeyGroup()) .setKeyGroup(userRegistrationDTO.getKeyGroup())
.setFlagExtraUser("S") .setFlagExtraUser("S")
.setCryptPassword(true); .setCryptPassword(true);

View File

@@ -15,14 +15,17 @@ import it.integry.ems_model.config.EmsRestConstants;
import it.integry.ems_model.entity.StbFilesAttached; import it.integry.ems_model.entity.StbFilesAttached;
import it.integry.ems_model.entity.StbUser; import it.integry.ems_model.entity.StbUser;
import it.integry.ems_model.types.OperationType; import it.integry.ems_model.types.OperationType;
import it.integry.ems_model.utility.*; import it.integry.ems_model.utility.Query;
import it.integry.ems_model.utility.UtilityDB;
import it.integry.ems_model.utility.UtilityLocalDate;
import it.integry.ems_model.utility.UtilityString;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Date; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Service @Service
@@ -61,8 +64,6 @@ public class UserService {
UtilityEntity.throwEntityException(stbUser); UtilityEntity.throwEntityException(stbUser);
userCacheService.invalidateCache();
return stbUser; return stbUser;
} }
@@ -91,11 +92,11 @@ public class UserService {
entityProcessor.processEntity(stbUser, multiDBTransactionManager); entityProcessor.processEntity(stbUser, multiDBTransactionManager);
Date passwordEndtime = EmsRestConstants.DATE_NULL; LocalDateTime passwordEndtime = EmsRestConstants.LOCAL_DATE_TIME_NULL;
if (stbUser.getFlagPasswordExpiring().equalsIgnoreCase("S") && if (stbUser.getFlagPasswordExpiring().equalsIgnoreCase("S") &&
stbUser.getPasswordExpiresDays() != 0) { stbUser.getPasswordExpiresDays() != 0) {
passwordEndtime = UtilityDate.dateAdd(new Date(), stbUser.getPasswordExpiresDays()); passwordEndtime = LocalDateTime.now().plusDays(stbUser.getPasswordExpiresDays());
} }
stbUser stbUser
@@ -111,8 +112,6 @@ public class UserService {
UtilityEntity.throwEntityException(stbUser); UtilityEntity.throwEntityException(stbUser);
userCacheService.invalidateCache();
return stbUser; return stbUser;
} }
@@ -143,18 +142,7 @@ public class UserService {
} }
public List<String> retrieveAvailableProfiles(String username, String password) { public List<String> retrieveAvailableProfiles(String username, String password) {
return userCacheService.retrieveProfilesOfUser(username, password, requestDataDTO.getApplication());
List<String> profiles;
profiles = userCacheService.retrieveProfilesOfUser(username, password, requestDataDTO.getApplication());
if (profiles.isEmpty()) {
// SELEZIONE CICLICA IN TUTTI I DB SPECIFICATI
userCacheService.invalidateCache();
profiles = userCacheService.retrieveProfilesOfUser(username, password, requestDataDTO.getApplication());
}
return profiles;
} }
public String getSignatureIdAttach(String username) throws Exception { public String getSignatureIdAttach(String username) throws Exception {

View File

@@ -1,5 +1,6 @@
package it.integry.ems_model.entity; package it.integry.ems_model.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonTypeName;
import it.integry.common.var.CommonConstants; import it.integry.common.var.CommonConstants;
@@ -7,6 +8,7 @@ import it.integry.ems_model.annotation.*;
import it.integry.ems_model.base.EntityBase; import it.integry.ems_model.base.EntityBase;
import it.integry.ems_model.utility.Query; import it.integry.ems_model.utility.Query;
import it.integry.ems_model.utility.UtilityDB; import it.integry.ems_model.utility.UtilityDB;
import it.integry.ems_model.utility.UtilityPassword;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.kie.api.definition.type.PropertyReactive; import org.kie.api.definition.type.PropertyReactive;
@@ -96,7 +98,7 @@ public class StbUser extends EntityBase {
private String lastPasswords; private String lastPasswords;
@SqlField(value = "password_endtime") @SqlField(value = "password_endtime")
private Date passwordEndtime; private LocalDateTime passwordEndtime;
@SqlField(value = "password_expires_days", defaultObjectValue = "180") @SqlField(value = "password_expires_days", defaultObjectValue = "180")
private Integer passwordExpiresDays; private Integer passwordExpiresDays;
@@ -422,11 +424,11 @@ public class StbUser extends EntityBase {
return this; return this;
} }
public Date getPasswordEndtime() { public LocalDateTime getPasswordEndtime() {
return passwordEndtime; return passwordEndtime;
} }
public StbUser setPasswordEndtime(Date passwordEndtime) { public StbUser setPasswordEndtime(LocalDateTime passwordEndtime) {
this.passwordEndtime = passwordEndtime; this.passwordEndtime = passwordEndtime;
return this; return this;
} }
@@ -670,4 +672,12 @@ public class StbUser extends EntityBase {
JrlFlavUsers jrlFlavUsers = new JrlFlavUsers(); JrlFlavUsers jrlFlavUsers = new JrlFlavUsers();
jrlFlavUsers.deleteAllEntities(connection, this); jrlFlavUsers.deleteAllEntities(connection, this);
} }
@JsonIgnore
public String getPasswordDecoded() {
if (this.password != null)
return UtilityPassword.sysDcdPss(this.password);
return null;
}
} }

View File

@@ -0,0 +1,60 @@
package it.integry.ems_model.utility;
public class UtilityPassword {
/**
* Replica della funzione SQL Server dbo.sys_dcd_pss in Java 1.8.
*
* @param input stringa in ingresso (equivalente a @input VARCHAR(MAX))
* @return stringa "decrypted" (equivalente al RETURN VARCHAR(MAX))
*/
public static String sysDcdPss(String input) {
if (input == null || input.isEmpty()) {
return input;
}
// In SQL:
// DECLARE @decrypted AS VARCHAR(MAX)
// SELECT @decrypted = SUBSTRING(@input, 1, 1)
StringBuilder decrypted = new StringBuilder();
decrypted.append(input.charAt(0));
int minAscii = 0;
int maxAscii = 122;
// DECLARE @firstCharAscii AS INT = ASCII(@decrypted);
int firstCharAscii = (int) decrypted.charAt(0);
// In SQL l'indice @i parte da 0 e il WHILE usa DATALENGTH(@input)
// con caratteri 1-based: substring(@input, @i, 1).
// In Java useremo un for su index 1-based per aderire alla logica.
int dataLength = input.length(); // DATALENGTH per VARCHAR = numero di caratteri
int i = 0;
while (i < dataLength) {
i = i + 1;
// IF @i = 1 CONTINUE
if (i == 1) {
continue;
}
// substring(@input, @i, 1) -> input.charAt(i - 1) in Java (0-based)
int currentCharAscii = (int) input.charAt(i - 1);
if (currentCharAscii <= maxAscii) {
currentCharAscii = currentCharAscii - firstCharAscii;
if (currentCharAscii <= minAscii) {
currentCharAscii = currentCharAscii + maxAscii;
}
} else {
currentCharAscii = currentCharAscii - firstCharAscii;
}
decrypted.append((char) currentCharAscii);
}
return decrypted.toString();
}
}

View File

@@ -158,30 +158,24 @@ public class SystemController {
@RequestParam(value = "dataInizio") Date dataInizio, @RequestParam(value = "dataInizio") Date dataInizio,
@RequestParam(value = "dataFine") Date dataFine) throws Exception { @RequestParam(value = "dataFine") Date dataFine) throws Exception {
String configuration = "INTEGRY"; String configuration = "INTEGRY";
MultiDBTransactionManager dbIntegry = new MultiDBTransactionManager(configuration); try (MultiDBTransactionManager dbIntegry = new MultiDBTransactionManager(configuration)) {
String query =
"SELECT dbo.f_escape_json(log.processo) as 'processo', "
+ " dbo.f_escape_json(Replace(Replace(log.attivita, '[', ''), ']', ':')) as 'attivita', "
+ " log.tipoAttivita as 'tipoAttivita', "
+ " log.novita "
+ " FROM dbo.integry_changeLog( " + UtilityDB.valueToString(partIva) + ", " +
UtilityDB.valueDateToString(dataInizio, CommonConstants.DATE_FORMAT_YMD) + ", " +
UtilityDB.valueDateToString(dataFine, CommonConstants.DATE_FORMAT_YMD) + ") log "
+ "ORDER BY 3, 1, 2 ";
String query = List<ChangeLogDTO> changeLog = UtilityDB.executeSimpleQueryDTO(dbIntegry.getPrimaryConnection(), query, ChangeLogDTO.class);
"SELECT dbo.f_escape_json(log.processo) as 'processo', "
+ " dbo.f_escape_json(Replace(Replace(log.attivita, '[', ''), ']', ':')) as 'attivita', "
+ " log.tipoAttivita as 'tipoAttivita', "
+ " log.novita "
+ " FROM dbo.integry_changeLog( " + UtilityDB.valueToString(partIva) + ", " +
UtilityDB.valueDateToString(dataInizio, CommonConstants.DATE_FORMAT_YMD) + ", " +
UtilityDB.valueDateToString(dataFine, CommonConstants.DATE_FORMAT_YMD) + ") log "
+ "ORDER BY 3, 1, 2 ";
if (changeLog != null && !changeLog.isEmpty()) {
List<ChangeLogDTO> changeLog = null; return ServiceRestResponse.createPositiveResponse(changeLog);
}
try {
changeLog = UtilityDB.executeSimpleQueryDTO(dbIntegry.getPrimaryConnection(), query, ChangeLogDTO.class);
} finally {
dbIntegry.close();
}
if (changeLog != null && !changeLog.isEmpty()) {
return ServiceRestResponse.createPositiveResponse(changeLog);
} }
return ServiceRestResponse.createPositiveResponse(); return ServiceRestResponse.createPositiveResponse();
@@ -611,7 +605,7 @@ public class SystemController {
activity.setTipoAnag("C"); activity.setTipoAnag("C");
activity.setFlagTipologia("A"); activity.setFlagTipologia("A");
LocalDateTime dataInizio = UtilityLocalDate.localDateTimeFromDate(dataInizioParm); LocalDateTime dataInizio = UtilityLocalDate.localDateTimeFromDate(dataInizioParm);
LocalDateTime dataFine = UtilityLocalDate.localDateTimeFromDate(dataFineParm); LocalDateTime dataFine = UtilityLocalDate.localDateTimeFromDate(dataFineParm);
activity.setEffectiveTime(dataInizio); activity.setEffectiveTime(dataInizio);
activity.setEffectiveEndtime(dataFine); activity.setEffectiveEndtime(dataFine);
activity.setActivityDescription(HtmlUtils.htmlUnescape(activity.getActivityDescription())); activity.setActivityDescription(HtmlUtils.htmlUnescape(activity.getActivityDescription()));
@@ -833,7 +827,7 @@ public class SystemController {
stbActivity.getCodJcom(), stbActivity.getActivityDescription()); stbActivity.getCodJcom(), stbActivity.getActivityDescription());
List<String> utenti = new ArrayList<>(); List<String> utenti = new ArrayList<>();
if (stbActivity.getUserName().equalsIgnoreCase("DEV")|| stbActivity.getUserName().equalsIgnoreCase("T0003")) { if (stbActivity.getUserName().equalsIgnoreCase("DEV") || stbActivity.getUserName().equalsIgnoreCase("T0003")) {
utenti.add("F0003"); utenti.add("F0003");
utenti.add("F0237"); utenti.add("F0237");
utenti.add("F0060"); utenti.add("F0060");