// Copyright © 2015 HSL <https://www.hsl.fi>
// This program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses.
package fi.hsl.parkandride.config;
import com.querydsl.sql.postgresql.PostgreSQLQueryFactory;
import fi.hsl.parkandride.back.*;
import fi.hsl.parkandride.back.prediction.PredictionDao;
import fi.hsl.parkandride.back.prediction.PredictorDao;
import fi.hsl.parkandride.core.back.*;
import fi.hsl.parkandride.core.domain.prediction.Predictor;
import fi.hsl.parkandride.core.domain.prediction.RelativizedAverageOfPreviousWeeksPredictor;
import fi.hsl.parkandride.core.service.*;
import fi.hsl.parkandride.core.service.reporting.*;
import org.jasypt.util.password.PasswordEncryptor;
import org.jasypt.util.password.StrongPasswordEncryptor;
import org.joda.time.format.ISOPeriodFormat;
import org.joda.time.format.PeriodFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.inject.Inject;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.SecureRandom;
@Configuration
@Import(JdbcConfiguration.class)
@EnableTransactionManagement(proxyTargetClass = true)
@EnableScheduling
public class CoreConfiguration {
private static final Logger log = LoggerFactory.getLogger(CoreConfiguration.class);
private static final String SECURITY_TOKEN_SECRET = "security.token.secret";
@Inject PostgreSQLQueryFactory queryFactory;
@Inject PlatformTransactionManager transactionManager;
@Value("${" + SECURITY_TOKEN_SECRET + "}") String tokenSecret;
@Value("${security.token.expires}") String tokenExpires;
@Value("${password.expires}") String passwordExpires;
@Value("${password.reminder}") String passwordReminder;
private PeriodFormatter periodFormatter = ISOPeriodFormat.standard();
@Bean
public AuthenticationService authenticationService() {
return new AuthenticationService(
userRepository(),
passwordEncryptor(),
tokenSecret(),
periodFormatter.parsePeriod(tokenExpires),
periodFormatter.parsePeriod(passwordExpires),
periodFormatter.parsePeriod(passwordReminder)
);
}
String tokenSecret() {
String secret = tokenSecret;
int minLength = AuthenticationService.SECRET_MIN_LENGTH;
if (secret.length() < minLength) {
log.warn("The value of {} is shorter than {} characters; replacing it with a randomly generated value. " +
"This may cause tokens to expire prematurely.", SECURITY_TOKEN_SECRET, minLength);
int[] chars = new SecureRandom()
.ints(minLength)
.map(i -> (char) i)
.toArray();
return new String(chars, 0, chars.length);
} else {
return secret;
}
}
@Bean
public UserService userService() {
return new UserService(userRepository(), authenticationService(), validationService());
}
@Bean
public PasswordEncryptor passwordEncryptor() {
return new StrongPasswordEncryptor();
}
@Bean
public UserRepository userRepository() {
return new UserDao(queryFactory);
}
@Bean
public ContactRepository contactRepository() {
return new ContactDao(queryFactory);
}
@Bean
public ContactService contactService() {
return new ContactService(contactRepository(), validationService());
}
@Bean
public OperatorRepository operatorRepository() {
return new OperatorDao(queryFactory);
}
@Bean
public OperatorService operatorService() {
return new OperatorService(operatorRepository(), validationService());
}
@Bean
public TranslationService translationService() {
return new TranslationService();
}
@Bean
public ExcelUtil excelUtil(MessageSource messageSource) {
return new ExcelUtil(messageSource);
}
@Bean
public HubsAndFacilitiesReportService hubsAndFacilitiesReportService() {
return new HubsAndFacilitiesReportService(facilityService(), operatorService(), contactService(), hubService(), utilizationRepository(), regionRepository(), translationService(), facilityHistoryService());
}
@Bean
public RequestLogReportService requestLogReportService() {
return new RequestLogReportService();
}
@Bean
public FacilityUsageReportService facilityUsageReportService() {
return new FacilityUsageReportService(facilityService(), operatorService(), contactService(), hubService(), utilizationRepository(), regionRepository(), translationService(), facilityHistoryService());
}
@Bean
public MaxUtilizationReportService maxUtilizationReportService() {
return new MaxUtilizationReportService(facilityService(), operatorService(), contactService(), hubService(), utilizationRepository(), regionRepository(), translationService(), facilityHistoryService());
}
@Bean
public FacilityHistoryService facilityHistoryService() {
return new FacilityHistoryService(facilityHistoryRepository(), facilityRepository());
}
@Bean
public FacilityRepository facilityRepository() {
return new FacilityDao(queryFactory, facilityHistoryRepository());
}
@Bean
public FacilityHistoryRepository facilityHistoryRepository() {
return new FacilityHistoryDao(queryFactory);
}
@Bean
public FacilityService facilityService() {
return new FacilityService(facilityRepository(), utilizationRepository(), contactRepository(), validationService(), predictionService());
}
@Bean
public ValidationService validationService() {
return new ValidationService();
}
@Bean
public HubRepository hubRepository() {
return new HubDao(queryFactory);
}
@Bean
public HubService hubService() {
return new HubService(hubRepository(), validationService());
}
@Bean
public PredictionService predictionService() {
return new PredictionService(utilizationRepository(), predictionRepository(), predictorRepository(), facilityRepository(), transactionManager, lockRepository(), predictors());
}
@Bean
public LockRepository lockRepository() {
return new LockDao(queryFactory, validationService(), currentNodeLockName());
}
@Bean
public Predictor[] predictors() {
return new Predictor[]{new RelativizedAverageOfPreviousWeeksPredictor()};
}
@Bean
public UtilizationRepository utilizationRepository() {
return new UtilizationDao(queryFactory);
}
@Bean
public RegionRepository regionRepository() {
return new RegionDao(queryFactory);
}
@Bean
public PredictionRepository predictionRepository() {
return new PredictionDao(queryFactory, validationService());
}
@Bean
public PredictorRepository predictorRepository() {
return new PredictorDao(queryFactory, validationService());
}
@Bean
public RequestLogRepository requestLogRepository() {
return new RequestLogDao(queryFactory);
}
@Bean
public BatchingRequestLogService batchingRequestLogService(RequestLogRepository requestLogRepository) {
return new BatchingRequestLogService(requestLogRepository);
}
@Bean
public String currentNodeLockName() {
String randomString = new BigInteger(40, new SecureRandom()).toString(32);
try {
return InetAddress.getLocalHost().getHostAddress() + "-" + randomString;
} catch (UnknownHostException e) {
return randomString;
}
}
}